这是 GNU Emacs Lisp 参考手册 对应于 Emacs 版本 30.2.
版权所有 © 1990–1996, 1998–2025 自由软件基金会
本文件允许在GNU自由文档许可证 1.3 版或自由软件基金会发布的任何后续版本的条款下复制、分发和/或修改;不变部分为“GNU通用公共许可证”,封面文字为“GNU手册”,封底文字如下(a)所示。许可证副本包含在题为“GNU自由文档许可证”的部分中。
(a)自由软件基金会(FSF)的封底文字是:“您可以自由复制和修改本 GNU手册。从 FSF 购买副本将支持其开发 GNU 并促进软件自由。”
display Property
GNU Emacs 文本编辑器的绝大部分代码,均由名为 Emacs Lisp 的编程语言编写而成。你可以用 Emacs Lisp 编写新代码,并将其作为编辑器扩展加载使用。不过,Emacs Lisp 并非只是一门扩展语言:它本身就是一套完整的计算机编程语言,可像其他编程语言一样通用。
由于 Emacs Lisp 专为编辑器场景设计,它自带文本扫描、解析等专用能力,同时也支持文件、缓冲区、显示、子进程等相关功能。Emacs Lisp 与编辑功能深度集成:编辑命令本身就是可在 Lisp 程序中直接调用的函数,自定义参数则是普通的 Lisp 变量。
本手册力求完整介绍 Emacs Lisp。若你是初学者,可阅读由 Bob Chassell 撰写、自由软件基金会出版的 《Emacs Lisp 编程入门》。本手册假定你已相当熟悉 Emacs 的基本编辑操作,相关基础内容请参阅 《GNU Emacs 手册》。
一般而言,前面章节介绍 Emacs Lisp 中与多数编程语言共通的特性,后续章节则讲解 Emacs Lisp 独有的、或与编辑功能直接相关的特性。
本文档 为 GNU Emacs Lisp 参考手册,对应 Emacs 版本:30.2.
本手册历经多次修订,内容已近乎完整,但仍非完美无缺。部分主题尚未覆盖,原因或是我们认为其属于次要内容(如多数独立模式),或是相关章节仍待撰写。因无法完整阐述,我们有意省略了若干部分。
手册中已覆盖的内容应完全准确,因此其中任何表述 —— 从具体示例、描述文字,到章节与小节的编排顺序 —— 都欢迎批评指正。若某处内容令人困惑,或是你必须查阅源码、动手实验才能了解手册未提及的知识,那么手册或许需要修正。敬请告知我们。
使用本手册时,若发现错误,恳请尽快提交更正。如果你为某个函数或一组函数想到了简洁、实用的示例,请尽力整理并发送过来。评论时请注明对应的节点名、函数名或变量名,并说明你所指正的版本号。
请通过 M-x report-emacs-bug 发送意见与更正。详情,See 报告错误 in The GNU Emacs Manual。
Lisp(表处理语言,LISt Processing language)于 20 世纪 50 年代末在麻省理工学院首次开发,用于人工智能研究。Lisp 语言的强大能力使其同样适用于其他场景,例如编写编辑命令。
多年来已经出现了数十种 Lisp 实现,每种都有其独特之处。其中许多都受 Maclisp 启发 ——Maclisp 是 20 世纪 60 年代麻省理工学院 MAC 项目所开发的。最终,Maclisp 后续分支的实现者们共同制定了一套 Lisp 系统标准,称为Common Lisp。与此同时,麻省理工学院的 Gerry Sussman 与 Guy Steele 开发了一门简洁但功能强大的 Lisp 方言,名为Scheme。
GNU Emacs Lisp 主要受 Maclisp 启发,也少量借鉴了 Common Lisp。如果你了解 Common Lisp,会发现许多相似之处。不过,为了降低 GNU Emacs 的内存占用,Common Lisp 的很多特性被省略或简化。这些简化有时幅度很大,可能会让 Common Lisp 用户感到困惑。我们会偶尔指出 GNU Emacs Lisp 与 Common Lisp 的区别。如果你不了解 Common Lisp,也无需担心:本手册内容是自包含的。
可以通过 cl-lib 库实现一定程度的 Common Lisp 模拟,See 概述 in Common Lisp Extensions.
Emacs Lisp 完全没有受到 Scheme 的影响;但 GNU 项目有一套 Scheme 实现,名为 Guile。我们在所有需要支持扩展的新 GNU 软件中都使用它。
本节说明本手册所使用的符号约定。你可以先跳过本节,需要时再回头查阅。
在本手册中,“Lisp 读取器” 和 “Lisp 打印器” 分别指 Lisp 中负责将 Lisp 对象的文本表示转换为实际 Lisp 对象,以及进行反向转换的程序。更多细节,See 打印表示与读入语法。阅读本手册的你被视为程序员,文中直接以 “you你” 称呼。用户则是指使用 Lisp 程序(包括你编写的程序)的人。
Lisp 代码示例会像这样排版:(list 1 2 3)。表示元语法变量或所描述函数的参数名称会像这样排版:first-number。
nil 和 t ¶在 Emacs Lisp 中,符号 nil 有三种不同含义:其一,它是名为 ‘nil’ 的符号;其二,它代表逻辑布尔值 false;其三,它表示空列表 —— 即包含零个元素的列表。当 nil 作为变量使用时,其值始终为 nil。
对于 Lisp 读取器而言,‘()’ 和 ‘nil’ 完全等价:它们指向同一个对象(符号 nil)。这两种书写形式仅为方便人类阅读而设计。Lisp 读取器读取 ‘()’ 或 ‘nil’ 后,无法区分程序员实际书写的是哪一种形式。
在本手册中,若想强调 “空列表” 这一含义,我们会写作 ();若想强调布尔值 false 这一含义,则写作 nil。这种写法也适用于 Lisp 程序编写,是值得遵循的良好约定。
(cons 'foo ()) ; 强调空列表 (setq foo-flag nil) ; 强调布尔值 false
在需要布尔值的上下文环境中,任何非 nil 的值都会被视为 true。不过,t 是表示布尔值 true 的首选形式。当你需要选择一个值来代表 true 且无其他选择依据时,应使用 t。符号 t 的值始终为 t。
在 Emacs Lisp 中,nil 和 t 是特殊符号,它们的求值结果始终是自身。因此,在程序中将它们用作常量时无需加引号。若尝试修改它们的值,会触发 设置常量错误(setting-constant error)。See 永不改变的变量.
若 object 是两个标准布尔值(t 或 nil)之一,则返回非 nil 值。
可以被求值的 Lisp 表达式称为 form (形式)。对一个 form 求值总会产生一个结果,该结果是一个 Lisp 对象。在本手册的示例中,这一过程用符号 ‘⇒’ 表示:
(car '(1 2))
⇒ 1
你可以将其读作:“(car '(1 2)) 求值结果为 1”.
当一个 form 是宏调用时,它会展开为一个新的 form 供 Lisp 求值。我们用 ‘→’ 表示展开结果。展开后 form 的求值结果可能会展示,也可能不展示。
(third '(a b c))
→ (car (cdr (cdr '(a b c))))
⇒ c
为了辅助描述某个 form形式,我们有时会展示另一个效果完全相同的形式。两个形式的严格等价关系用 ‘≡’ 表示。
(make-sparse-keymap) ≡ (list 'keymap)
本手册中的许多示例在求值时会打印文本。如果你在 Lisp 交互缓冲区(如 *scratch* 缓冲区)中运行示例代码,只需在示例的右括号后按下 C-j,打印出的文本就会插入到缓冲区中。如果你通过其他方式(如使用 eval-region 函数求值)运行示例,打印的文本会显示在回显区。
本手册的示例中,无论文本输出到何处,打印内容均使用符号 ‘⊣’ 标注。形式求值后返回的值则在单独一行用 ‘⇒’ 标注。
(progn (prin1 'foo) (princ "\n") (prin1 'bar))
⊣ foo
⊣ bar
⇒ bar
部分示例会触发错误。这种情况下,通常会在回显区显示一条错误信息。我们在以 ‘error→’ 开头的一行中展示错误信息。注意:‘error→’ 本身并不会出现在回显区中。
(+ 23 'x) error→ Wrong type argument: number-or-marker-p, x error→ 参数类型错误:应为数值或标记类型,实际为 x
有些示例会通过展示文本修改前后的状态,来描述对缓冲区内容的改动。这类示例会把对应缓冲区的内容,放在两行包含缓冲区名称的虚线之间。此外,‘∗’ 用来表示光标位置(point)。(当然,光标标记并非缓冲区里的实际文本;它只是标识出当前光标位于哪两个字符之间。)
---------- Buffer: foo ----------
This is the ∗contents of foo.
---------- Buffer: foo ----------
(insert "changed ")
⇒ nil
---------- Buffer: foo ----------
This is the changed ∗contents of foo.
---------- Buffer: foo ----------
本手册对函数、变量、宏、命令、用户选项和特殊forms 采用统一格式进行描述。描述的第一行会包含该对象的名称,其后附带其参数(如果有)。 对象的类别 — 函数、变量或其他类型 — 会出现在该行开头。 后续行是具体说明,有时会附带示例。
在函数描述中,首先出现的是被描述函数的名称,同一行紧接着是参数名列表。这些参数名也会在描述正文中使用,用来代表参数的值。
参数列表中出现关键字 &optional,表示其后的参数可以省略(省略的参数默认为 nil)。调用函数时不要写 &optional。
关键字 &rest(其后必须紧跟一个参数名)表示后面可以跟任意数量的参数。&rest 后面的这个参数名,会以列表形式接收传给函数的所有剩余参数。调用函数时不要写 &rest。
下面是一个虚构函数 foo 的描述:
函数 foo 用 integer2 减去 integer1,然后将其余所有参数加到结果上。如果没有提供 integer2,则默认使用数值 19。
(foo 1 5 3 9)
⇒ 16
(foo 5)
⇒ 14
更普遍的,
(foo w x y...) ≡ (+ (- x w) y...)
按照约定,任何名称中包含类型名的参数(例如 integer、integer1 或 buffer),都要求属于该类型。类型的复数形式(如 buffers)通常表示该类型对象的列表。名为 object 的参数可以是任意类型。(有关 Emacs 对象类型列表,see Lisp 数据类型。)名称带有其他含义的参数(如 new-file)则是该函数专用的;如果函数有文档字符串,其中会说明参数类型(see 文档)。
关于被 &optional 和 &rest 修饰的参数更完整的说明,See Lambda 表达式。
命令、宏和特殊形式的描述格式相同,只是把开头的 ‘Function’ 分别换成‘Command’、‘Macro’ 或 ‘Special Form’。命令只是可以交互式调用的函数;宏对参数的处理方式与函数不同(参数不被求值),但描述形式一致。
宏和特殊形式的描述会使用更复杂的表示法来指定可选参数和重复参数,因为它们可以用更复杂的方式把参数列表拆分为独立参数。‘[optional-arg]’ 表示 ‘optional-arg’ 是可选参数;‘repeated-args…’ 表示零个或多个参数。当多个参数被分组为更深层的列表结构时,会使用圆括号。示例如下:
这个虚构的特殊形式实现一个循环,每次迭代先执行 body 中的表达式,再对变量 var 递增。第一次迭代时,变量取值为 from;后续迭代每次加 1(若指定了 inc 则按 inc 递增)。如果 var 等于 to,则在执行 body 之前退出循环。示例:
(count-loop (i 0 10) (prin1 i) (princ " ") (prin1 (aref vector i)) (terpri))
如果省略 from 和 to,则循环开始前将 var 绑定为 nil,且每次迭代开始时,若 var 非-nil 则退出循环。示例:
(count-loop (done)
(if (pending)
(fixit)
(setq done t)))
在这个特殊形式里,参数 from 和 to 是可选的,但必须同时出现或同时省略。如果它们出现,还可以额外指定 inc。这些参数与 var 一起被放在一个列表里,以区别于 body — body 包含该形式中所有剩余元素。
变量 是一个可以被绑定 (或 赋值)到某个对象上的名称。变量所绑定的对象称为它的value值;我们也说该变量保存这个值。尽管几乎所有变量都可以由用户设置,但有一类变量专门供用户修改,这类变量称为user options用户选项。普通变量和用户选项所使用的描述格式与函数类似,只是没有参数。
下面是虚构变量 electric-future-map 的描述示例:
该变量的值是一个完整的 keymap键盘映射表,供 ‘Electric Command Future mode’ 使用。该映射表中的函数可以让你编辑尚未打算执行的命令。
用户选项的描述格式完全相同,只是将开头的 ‘Variable’ 替换为 ‘User Option’。
以下这些功能可以提供当前所使用的 Emacs 版本信息。
此函数返回一个字符串,描述正在运行的 Emacs 版本。在错误报告中包含该字符串会很有用。
(emacs-version)
⇒ "GNU Emacs 26.1 (build 1, x86_64-unknown-linux-gnu,
GTK+ Version 3.16) of 2017-06-01"
如果 here 非-nil,该函数会将文本插入到缓冲区中光标之前,并返回 nil。当以交互式方式调用此函数时,它会在回显区打印相同信息;若提供前缀参数,则会使 here 为非-nil。
该变量的值表示 Emacs 的编译时间。其格式与 current-time 相同(see Time of Day);如果信息不可用,则为 nil。
emacs-build-time
⇒ (25194 55894 8547 617000)
(如果编译 Emacs 时 current-time-list 为 nil,则该时间戳为 (1651169878008547617 . 1000000000)。)
该变量的值是正在运行的 Emacs 版本字符串,例如 "26.1"。若值包含三个数字部分(如 "26.0.91"),表示这是一个未发布的测试版。(在 Emacs 26.1 之前,版本字符串末尾会多一个数字,该数字现在存放在 emacs-build-number 中,例如 "25.1.1"。)
Emacs 的主版本号,为整数类型。例如 Emacs 23.1 中,该值为 23。
Emacs 的次版本号,为整数类型。例如 Emacs 23.1 中,该值为 1。
一个整数,每次在同一目录下(不清理)编译 Emacs 时都会递增。该变量仅在开发 Emacs 时有用。
字符串类型,表示编译此 Emacs 所依据的代码仓库修订号。如果 Emacs 是在版本控制系统之外编译的,该值为 nil。
字符串类型,表示编译此 Emacs 所依据的代码仓库分支。绝大多数情况下为 "master"。如果 Emacs 是在版本控制系统之外编译的,该值为 nil。
本手册最初由 Robert Krawitz、Bil Lewis、Dan LaLaiberte、Richard M. Stallman 与 Chris Welty 编写,他们是 GNU 手册小组的志愿者,这项工作历时数年完成。Robert J. Chassell 协助审阅与编辑本手册,工作得到美国国防部高级研究计划局(DARPA)ARPA 第 6082 号订单的支持,该项目由计算逻辑公司的 Warren A. Hunt, Jr. 负责协调。此后新增的章节由 Miles Bader、Lars Brinkhoff、Chong Yidong、Kenichi Handa、Lute Kamstra、Juri Linkov、Glenn Morris、Thien‑Thi Nguyen、Dan Nicolaescu、Martin Rudalics、Kim F. Storm、Luc Teirlinck、Eli Zaretskii 及其他人士撰写。
感谢以下人士提供修正意见:Drew Adams, Juanma Barranquero, Karl Berry, Jim Blandy, Bard Bloom, Stephane Boucher, David Boyes, Alan Carroll, Richard Davis, Lawrence R. Dodd, Peter Doornbosch, David A. Duff, Chris Eich, Beverly Erlebacher, David Eckelkamp, Ralf Fassel, Eirik Fuller, Stephen Gildea, Bob Glickstein, Eric Hanchrow, Jesper Harder, George Hartzell, Nathan Hess, Masayuki Ida, Dan Jacobson, Jak Kirman, Bob Knighten, Frederick M. Korz, Joe Lammens, Glenn M. Lewis, K. Richard Magill, Brian Marick, Roland McGrath, Stefan Monnier, Skip Montanaro, John Gardiner Myers, Thomas A. Peterson, Francesco Potortì, Friedrich Pukelsheim, Arnold D. Robbins, Raul Rockwell, Jason Rumney, Per Starbäck, Shinichirou Sugou, Kimmo Suominen, Edward Tharp, Bill Trost, Rickard Westman, Jean White, Eduard Wiebe, Matthew Wilding, Carl Witty, Dale Worley, Rusty Wright, and David D. Zuhn.
如需更完整的贡献者名单,请查阅 Emacs 源代码仓库中对应的变更日志条目。
Lisp object对象 是 Lisp 程序使用和操作的数据单元。对我们而言,type类型 或 data type数据类型 是一组可能的对象集合。
每个对象至少属于一种类型。同一类型的对象具有相似的结构,通常可在相同的上下文中使用。类型之间可以重叠,一个对象可以属于两种或更多类型。因此,我们可以判断一个对象是否属于某一特定类型,但不能说一个对象唯一的类型是什么。
Emacs 内置了少量基础对象类型,所有其他类型都由这些类型构造而成,它们被称为 primitive types基本类型。每个对象有且仅属于一种基本类型。这些类型包括:integer整数、float浮点数、cons单元、symbol符号、string字符串、vector向量、hash-table哈希表、subr子程序、byte-code function字节码函数和recor记录,此外还有若干与编辑相关的特殊类型,如buffer缓冲区等。(See 编辑类型。)
每种基本类型都有对应的 Lisp 函数,用于检查一个对象是否属于该类型。
Lisp 与许多其他语言不同之处在于它的对象是 self-typing自描述类型:每个对象的基本类型隐含在对象自身中。例如,如果一个对象是向量,任何代码都不能把它当作数字;Lisp 本身就知道它是向量而非数字。
在大多数语言中,程序员必须为每个变量声明数据类型,类型由编译器知晓,但不体现在数据中。Emacs Lisp 中不存在这类类型声明。Lisp 变量可以存放任意类型的值,并且会完整保留你存入的值及其类型。(实际上,极少数 Emacs Lisp 变量只能接受特定类型的值。See 受限值变量。)
本章介绍 GNU Emacs Lisp 中每种标准类型的用途、打印表示和读入语法。有关如何使用这些类型的详细内容将在后续章节说明。
对象的 printed representation打印表示,是 Lisp 打印器(函数 prin1)为该对象生成的输出格式。每种数据类型都有唯一的打印表示。对象的 read syntax读入语法,是 Lisp 读取器(函数 read)对该对象所接受的输入格式。这一格式不一定唯一:很多对象都支持多种语法。See Lisp 对象的读取与打印。
在大多数情况下,一个对象的打印表示形式同时也是该对象的读取语法。不过,某些类型并没有对应的读取语法,因为在 Lisp 程序中把这类对象当作常量输入是没有意义的。这类对象会以 hash notation井号表示法 打印:由字符 ‘#<’ 开头,接着是一段描述性字符串(通常是类型名后跟对象名),最后以 ‘>’ 结尾。(之所以称为 “hash natation井号表示法”,是因为它以字符 ‘#’ 开头,该字符也叫 “hash井号” 或 “数字符号”。)例如:
(current-buffer)
⇒ #<buffer objects.texi>
井号表示法完全无法被读取,因此 Lisp 读取器只要遇到 ‘#<’,就会报 invalid-read-syntax(非法读入语法)错误。
在本章后续各节中,我们会在介绍每种 Lisp 数据类型时,同时说明它的读取语法与打印表示形式。例如, 查看 字符串类型 及其子小节可了解字符串的读取语法与打印表示;查看 向量类型 可获取向量的相关信息,依此类推。
在其他语言中,表达式就是文本,没有别的形态。而在 Lisp 中,表达式首先是一个 Lisp 对象,其次才是作为该对象读入语法的文本。通常不必刻意强调这一区别,但你必须心里有数,否则偶尔会非常困惑。
当你交互式求值一个表达式时,Lisp 解释器会先读取它的文本表示,构造出一个 Lisp 对象,然后再对这个对象求值(see Evaluation)。但读取与求值是两个独立的过程:读取只是根据文本返回对应的 Lisp 对象;这个对象之后可能被求值,也可能不会。关于基本读取函数 read 的说明,See 输入函数。
Emacs Lisp 通过特殊井号表示法表示许多特殊对象和结构。
没有读取语法的对象会以这种形式展示(see 打印表示与读入语法)。
名称为空字符串的已 intern 符号的打印表示(see 符号类型)。
这是 function 的简写形式,见 匿名函数。
名称为 foo 的未 intern 符号的打印表示是 ‘#:foo’(see 符号类型)。
打印循环结构时,用于表示结构自引用的位置,‘N’ 是起始列表编号:
(let ((a (list 1))) (setcdr a a)) => (1 . #0)
‘#N=’ 为一个对象命名,‘#N#’ 表示该对象。这样在重新读取时,它们会是同一个对象而非副本(see 循环对象的读取语法)。
以十六进制表示 ‘N’(如 ‘#x2a’)。
以八进制表示 ‘N’(如 ‘#o52’)。
以二进制表示 ‘N’(如 ‘#b101010’)。
字符串的文本属性(see 字符串中的文本属性)。
字符表(see 字符表类型)。
哈希表(see 哈希表类型)。
字符(see 基本字符语法)。
字节编译文件中的当前文件名(see 文档字符串与编译)。不建议在 Emacs Lisp 源文件中使用。
跳过接下来的 ‘N’ 个字符(see 注释)。用于字节编译文件,不建议在 Emacs Lisp 源文件中使用。
表示后续的表达式无法被 Emacs Lisp 读取器读取。该标记仅用于显示文本(当它比其他表示不可读表达式的方式更美观时),绝不会出现在任何 Lisp 文件中。
comment注释 是程序中仅供阅读程序的人理解所写的文本,对程序的含义没有任何影响。在 Lisp 中,未转义的分号(‘;’) 只要不在字符串或字符常量内部,就表示开始一段注释,注释持续到本行末尾。Lisp 读取器会忽略注释,它们不会成为 Lisp 系统中表示程序的 Lisp 对象的一部分。
‘#@count’ 结构会跳过接下来的 count 个字符,常用于由程序自动生成、包含二进制数据的注释。Emacs Lisp 字节编译器会在其输出文件中使用该结构(see 字节编译),但它并不适用于源文件。
关于注释的排版规范,See Tips on Writing Comments。
Emacs Lisp 中的类型分为两大类:一类与 Lisp 编程相关,另一类与 编辑功能相关。前者以各种形式存在于众多 Lisp 实现中,而后者是 Emacs Lisp 所独有的。
在底层实现中,整数分为两种:小整数(fixnum) 和大整数(bignum)。
fixnum 的取值范围取决于机器。其最小范围是 −536,870,912 到 536,870,911 (共 30 位,即 −2**29 到 2**29 − 1) 但很多机器会提供更宽的范围。
Bignum 可以拥有任意精度。会导致 fixnum 溢出的运算,将自动返回 bignum 作为结果。
所有数值都可以用 eql 或 = 比较;fixnum 还可以用 eq 比较。要判断一个整数是 fixnum 还是 bignum,你可以将它与 most-negative-fixnum 和 most-positive-fixnum 比较,也可以直接使用便捷谓词 fixnump 和 bignump 作用于任意对象。
整数的读取语法是一串(十进制)数字,开头可带符号,末尾可带一个句点。Lisp 解释器输出的打印表示不会带有前导的 ‘+’ 或末尾的 ‘.’。
-1 ; 整数 −1. 1 ; 整数 1. 1. ; 同样是整数 1. +1 ; 同样是整数 1.
更多信息,See 数值。
浮点数是计算机中科学计数法的等价形式;你可以把浮点数看作一个分数与一个 10 的幂的组合。有效数字的精确位数和指数的取值范围与具体机器相关;Emacs 使用 C 语言的 double 数据类型来存储数值,在内部它记录的是 2 的幂而非 10 的幂。
浮点数的书写形式必须满足以下至少一项:包含小数点(且小数点后至少有一位数字),包含指数部分,或两者都有。例如,‘1500.0’、‘+15e2’、‘15.0e+2’、‘+1500000e-3’ 和 ‘.15e4’ 是表示数值 1500 的五种浮点写法,它们是等价的。
更多信息,See 数值。
Emacs Lisp 中的 character字符 本质上就是一个整数。换句话说,字符是通过其字符编码来表示的。例如,字符 A 用 整数 65 表示。这也是它们通常的打印形式;详见 基本字符语法。
程序中偶尔会使用单个字符,但更常见的是操作 strings字符串—— 字符串是由字符组成的序列。 See 字符串类型。
字符串和缓冲区中的字符目前限定在 0 到 4194303 范围内(共 22 位,see Character Codes)。编码 0~127 是 ASCII 编码,其余为非-ASCII 编码(see Non-ASCII Characters)。用于表示键盘输入的字符范围要大得多,以便编码 Control、Meta、Shift 等修饰键。
有专门的函数用于生成便于人类阅读的字符文本描述,以供提示信息使用。 See 帮助信息中的字符描述。
由于字符本质上是整数,字符的打印形式是一个十进制整数。这虽然也可以作为字符的读取语法,但在 Lisp 程序中这样写字符并不清晰。你应当 始终 使用 Emacs Lisp 为字符提供的专用读取语法格式,这些语法格式以问号开头。
字母与数字字符的常用读取语法是:问号后跟字符本身。例如:‘?A’ 表示字符 A,‘?B’ 表示字符 ‘B’,‘?a’ 表示字符 a。
示例:
?Q ⇒ 81 ?q ⇒ 113
标点符号也可以使用同样的语法。但是,如果该标点在 Lisp 中具有特殊语法含义,就必须用 ‘\’ 进行转义。例如,‘?\(’ 用来表示左括号字符。同理,如果字符是 ‘\’ 本身,必须用第二个 ‘\’ 转义:‘?\\’。
可以用以下写法表示控制字符:control-g:‘?\a’、退格符:‘?\b’、制表符:‘?\t’、换行符:‘?\n’、垂直制表符:‘?\v’、换页符:‘?\f’、空格符:‘?\s’、回车符:‘?\r’、删除符:‘?\d’、转义符:‘?\e’。(‘?\s’ 后面跟一个减号时含义不同 —— 它会将 Super 修饰符应用到后面的字符上。)如下所示:
?\a ⇒ 7 ; control-g, C-g ?\b ⇒ 8 ; 退格 backspace, BS, C-h ?\t ⇒ 9 ; 制表符 tab, TAB, C-i ?\n ⇒ 10 ; 换行 newline, C-j ?\v ⇒ 11 ; 垂直制表符 vertical tab, C-k ?\f ⇒ 12 ; 换页符 formfeed character, C-l ?\r ⇒ 13 ; 回车符 carriage return, RET, C-m ?\e ⇒ 27 ; 转义符 escape character, ESC, C-[ ?\s ⇒ 32 ; 空格 space character, SPC ?\\ ⇒ 92 ; 反斜杠 backslash character, \ ?\d ⇒ 127 ; 删除符 delete character, DEL
这些以反斜杠开头的序列称为 转义序列escape sequences,因为反斜杠起到了转义字符的作用;这与 ESC 字符本身无关。‘\s’ 用于字符常量;在字符串常量中直接写空格即可。
对没有特殊转义含义的字符前面加反斜杠是允许且无害的,例如 ‘?\+’ 等价于 ‘?+’。大多数字符没有必要加反斜杠,但以下字符必须加反斜杠: ‘()[]\;"’,为避免混淆 Emacs 的 Lisp 编辑命令,以下字符建议加反斜杠:‘|'`#.,’。对于外观类似上述 ASCII 字符的 Unicode 字符,也应加反斜杠,避免阅读代码的人混淆。Emacs 会高亮一些未转义、容易混淆的字符(如‘‘’左单引号、‘’’右单引号)来提醒你。你也可以在空格、制表符等空白字符前加反斜杠。不过,更清晰的做法是使用易读的转义序列(如 ‘\t’ 或 ‘\s’),而不是直接写制表符或空格这类空白字符。(如果你确实写成「反斜杠 + 空格」的形式,应当在该字符常量后面多加一个空格,以便与后续文本分隔。)
除了用于重要特殊控制字符的专用转义序列外,Emacs 还提供了多种转义语法,可用于表示非-ASCII 文本字符。
?\N{NAME} 表示名称为 NAME 的 Unicode 字符。例如, ‘?\N{LATIN SMALL LETTER A WITH GRAVE}’ 等价于 ?à,表示 Unicode 字符 U+00E0。为方便输入多行字符串,名称中的空格可以替换为任意非空空白序列(如换行)。
?\N{U+X} 表示 Unicode 码点为 X 的字符,其中 X 是十六进制数。此外,?\uxxxx 和 ?\Uxxxxxxxx 分别表示码点 xxxx 和 xxxxxxxx,每个 x 为一位十六进制数字。例如:?\N{U+E0}、?\u00e0 、?\U000000E0 都等价于 ?à 与 ‘?\N{LATIN SMALL LETTER A WITH GRAVE}’。Unicode 标准只定义到码点 ‘U+10ffff’,若指定更高码点,Emacs 会报错。
?\xe0 是字符 à(带重音符的 a)。‘x’ 后可跟一位或多位十六进制数字,因此可表示任意字符编码。
?\002 表示字符 C-b。只有八进制编码不超过 777 的字符才能用这种方式表示。
这些转义序列也可用于字符串中,See 字符串中的非-ASCII 字符。
控制字符可以使用另一种读取语法来表示。它由问号、反斜杠、脱字符 ‘^’ 以及对应的非控制字符组成,字母大小写均可。例如,‘?\^I’ 和 ‘?\^i’ 都是字符 C-i(值为 9)的合法读取语法。
你也可以用 ‘C-’ 代替 ‘^’,因此 ‘?\C-i’ 等价于 ‘?\^I’ 和 ‘?\^i’:
?\^I ⇒ 9 ?\C-I ⇒ 9
在字符串和缓冲区中,只允许使用 ASCII 中存在的控制字符;但在键盘输入场景下,你可以通过 ‘C-’ 将任意字符变成控制字符。这类非-ASCII 控制字符的编码,会在对应非控制字符编码的基础上,加上 2**26 这一位。并非所有文本终端都能生成非-ASCII 控制字符,但在 X 窗口系统及其他窗口系统下可以很方便地生成。
由于历史原因,Emacs 将 DEL 字符视为 ? 的控制等价字符:
?\^? ⇒ 127 ?\C-? ⇒ 127
因此,目前无法通过 ‘\C-’ 来表示 Control-? 这个在 X 窗口系统下有实际意义的输入字符。想要修改这一点并不容易,因为很多 Lisp 文件都以这种方式引用 DEL。
对于表示文件或字符串中的控制字符,我们推荐使用 ‘^’ 语法;对于键盘输入中的控制字符,更推荐使用 ‘C-’ 语法。使用哪种写法不会影响程序含义,但会帮助阅读代码的人更好地理解意图。
meta character元字符 是按住 META 修饰键输入的字符。表示这类字符的整数会设置 A meta character is a character typed with the META modifier key. The integer that represents such a character has the 2**27 这一位。我们使用高位来表示元字符及其他修饰符,以便支持大范围的基础字符编码。
在字符串中,ASCII 字符附加 2**7 (第 7 位)即表示元字符;因此,能放进字符串里的元字符,编码范围是 128~255,它们是普通 ASCII 字符对应的元字符版本。关于字符串中 META 处理的细节,See 将键盘事件存入字符串。
元字符的读取语法使用 ‘\M-’。例如,‘?\M-A’ 表示 M-A。你可以将 ‘\M-’ 与八进制字符编码(见下文)、‘\C-’ 或其他字符语法组合使用。因此,M-A 可以写作 ‘?\M-A’ 或 ‘?\M-\101’。同理,C-M-b 可以写作 ‘?\M-\C-b’、‘?\C-\M-b’ 或 ‘?\M-\002’。
图形字符的大小写由其字符编码标识;例如,ASCII 区分字符 ‘a’ 和 ‘A’。但 ASCII 无法表示控制字符是大写还是小写。Emacs 使用 2**25 这一位来标识输入控制字符时按下了 Shift 键。这种区分仅在图形显示器(如 X 窗口系统的 GUI)下可行,文本终端不会上报这类信息。表示 Shift 位的 Lisp 语法是 ‘\S-’;因此,‘?\C-\S-o’ 或 ‘?\C-\S-O’ 表示 Shift-Ctrl-o 字符。
X 窗口系统还定义了另外三种可在字符中设置的修饰符位:hyper、super 和 alt。它们对应的语法分别是 ‘\H-’、‘\s-’ 和 ‘\A-’。(这些前缀区分大小写。)例如,‘?\H-\M-\A-x’ 表示 Alt-Hyper-Meta-x。(注意:单独的 ‘\s’ 且后面不带 ‘-’ 表示空格字符。) 从数值上看:alt 对应位值:2**22、super 对应位值:2**23、hyper 对应位值:2**24。
GNU Emacs Lisp 中的 symbol符号 是带有名称的对象。符号名称同时作为该符号的打印表示形式。在常规的 Lisp 使用场景中(仅使用一个符号表 obarray,see 创建与编入符号),符号的名称具有唯一性 —— 不存在两个名称相同的符号。
一个符号可作为变量、函数名使用,或用于存储属性列表;也可仅作为与其他所有 Lisp 对象相区分的标识,确保其在数据结构中的出现能被可靠识别。在特定上下文下,通常仅会用到上述一种用途,但你也可以独立地将同一个符号用于所有这些场景。
名称以冒号(‘:’)开头的符号称为 keyword symbol关键字符号。这类符号会自动充当常量,通常仅用于将未知符号与若干特定备选符号做比较。 See 永不改变的变量。
符号名称可包含任意字符。
Common Lisp 说明: 在 Common Lisp 中,小写字母会自动转换为大写(除非显式转义);而在 Emacs Lisp 中,大小写字母是完全不同的字符。
以下是多个符号名称示例。注意第四个示例中的 ‘+’ 需转义,避免被解析为数字;第六个示例则无需转义,因为名称的其余部分使其无法被识别为数字。
foo ; 符号名称为 ‘foo’ FOO ; 符号名称为 ‘FOO’,与 ‘foo’ 不同
1+ ; 符号名称为 ‘1+’ ; (而非 ‘+1’ — 后者是整数)。
\+1 ; 符号名称为 ‘+1’ ; (可读性较差)。
\(*\ 1\ 2\) ; 符号名称为 ‘(* 1 2)’ (更差的名称)。 +-*/_~!@$%^&=:<>{} ; 符号名称为 ‘+-*/_~!@$%^&=:<>{}’. ; 这些字符无需转义。
符号名称作为其打印表示形式的规则有两个例外:
sequence序列 是一种表示有序元素集合的 Lisp 对象。Emacs Lisp 中有两类序列:lists列表 和 arrays数组。
列表是最常用的序列类型。列表可容纳任意类型的元素,且可通过添加或者删除元素轻松修改其长度。关于列表的更多内容,参见下一小节。
数组是固定长度的序列,又可进一步细分为字符串(string)、向量(vector)、字符表(char-table)和布尔向量(bool-vector)。向量可容纳任意类型的元素;字符串的元素必须是字符;布尔向量的元素只能是 t 或 nil;字符表与向量类似,但可通过任意有效字符编码进行索引。字符串中的字符可像缓冲区中的字符一样拥有文本属性(see Text Properties),而向量即便元素恰好是字符,也不支持文本属性。
列表、字符串以及其他数组类型也具有重要的共同特性。例如,它们都有一个长度 l,并且所有元素都可以从 0 到 l 减 1 进行索引。有一类被称为序列函数的函数可以接受任意类型的序列。例如,length 函数可以返回任意序列的长度。See 序列、数组与向量。
通常来说,不可能两次读取到同一个序列对象,因为序列在被读取时总会重新创建。如果你两次读取同一个序列的读取语法,会得到内容相同但并非同一个对象的两个序列。只有一个例外:空列表 () 始终表示同一个对象 —— nil。
cons cell(Cons 单元) 是包含两个存储位的对象,分别称为 CAR 位和 CDR 位。每个位都可以存放任意 Lisp 对象。我们也将这个 Cons 单元的 CAR 位当前存放的对象称为它的 CAR,CDR 位同理。
list列表 是由一系列 Cons 单元串联而成的结构:每个 Cons 单元的 CDR 位,要么存放着下一个 Cons 单元,要么存放着空列表。空列表实际上就是符号 nil。详细,See 列表。由于绝大多数 Cons 单元都用作列表的一部分,我们把由 Cons 单元构成的任何结构统称为 list structure列表结构。
给 C 程序员的说明:Lisp 列表相当于由 Cons 单元构成的 linked list链表。因为 Lisp 中的指针是隐式的,我们不区分 Cons 单元位中是 “存放值” 还是 “指向值”。
因为 Cons 单元在 Lisp 中如此核心,我们也给不是 Cons 单元的对象起了一个名字:这类对象称为 atoms原子。
列表的读取语法与打印表示完全一致:由左圆括号、任意数量的元素、右圆括号组成。以下是列表示例:
(A 2 "A") ; 包含三个元素的列表 () ; 不含元素的列表(空列表) nil ; 不含元素的列表(空列表) ("A ()") ; 只有一个元素的列表:字符串"A ()"(A ()) ; 包含两个元素的列表:A和空列表 (A nil) ; 与上一行等价 ((A B C)) ; 只有一个元素的列表 ; (该元素本身是一个含三个元素的列表)。
在读取时,括号内的每个对象都会成为列表的一个元素。也就是说,每个元素都会生成一个 Cons 单元。该 Cons 单元的 CAR 位存放元素本身、CDR 位指向列表中的下一个 Cons 单元。最后一个 Cons 单元的 CDR 位被设为 nil
CAR 与 CDR 这两个名称来源于 Lisp 历史。最早的 Lisp 运行在 IBM 704 计算机上,该机将字分为地址部分(address)和减量部分(decrement);CAR 是提取寄存器地址部分内容的指令,CDR 是提取寄存器减量部分内容的指令。与之相对,Cons 单元因创建它们的函数 cons 而得名,而 cons 取自其用途:构造(construction)单元。
列表可以用图示来表示:把每个 cons 单元画成一对像多米诺骨牌一样的方框。(Lisp 读取器无法理解这种图示;文本表示法既能被人也能被计算机理解,而方框图示只能被人理解。)下图表示含有三个元素的列表 (rose violet buttercup):
--- --- --- --- --- ---
| | |--> | | |--> | | |--> nil
--- --- --- --- --- ---
| | |
| | |
--> rose --> violet --> buttercup
在这个图示中,每个方框代表一个可以存放或引用任意 Lisp 对象的槽位(slot)。每一对方框代表一个 cons 单元。每一根箭头代表对一个 Lisp 对象的引用,该对象可以是原子,也可以是另一个 cons 单元。
在这个例子里:第一个方框存放第一个 cons 单元的 CAR,引用或存放着符号 rose。第二个方框存放第一个 cons 单元的 CDR,引用下一对方框,也就是第二个 cons 单元。第二个 cons 单元的 CAR 是 violet,它的 CDR 是第三个 cons 单元。第三个(也是最后一个)cons 单元的 CDR 是 nil。
下面是同一个列表 (rose violet buttercup) 的另一种画法:
--------------- ---------------- ------------------- | car | cdr | | car | cdr | | car | cdr | | rose | o-------->| violet | o-------->| buttercup | nil | | | | | | | | | | --------------- ---------------- -------------------
不含任何元素的列表就是 empty list空列表,它和符号 nil 完全等价。换句话说:nil 既是符号,也是列表。
下面是列表 (A ())(等价于 (A nil))的方框箭头图示:
--- --- --- ---
| | |--> | | |--> nil
--- --- --- ---
| |
| |
--> A --> nil
下面是一个更复杂的例子:三元素列表 ((pine needles) oak maple),它的第一个元素本身又是一个双元素列表:
--- --- --- --- --- ---
| | |--> | | |--> | | |--> nil
--- --- --- --- --- ---
| | |
| | |
| --> oak --> maple
|
| --- --- --- ---
--> | | |--> | | |--> nil
--- --- --- ---
| |
| |
--> pine --> needles
同一个列表用第二种方框表示法画出来是这样:
-------------- -------------- --------------
| car | cdr | | car | cdr | | car | cdr |
| o | o------->| oak | o------->| maple | nil |
| | | | | | | | | |
-- | --------- -------------- --------------
|
|
| -------------- ----------------
| | car | cdr | | car | cdr |
------>| pine | o------->| needles | nil |
| | | | | |
-------------- ----------------
Dotted pair notation点对表示法 是用于 cons 单元的通用语法,会显式表示 CAR 和 CDR。在这种语法中,(a . b) 表示一个 cons 单元,其 CAR 为对象 a,CDR 为对象 b。点对表示法比列表语法更通用,因为 CDR 不必是列表。但在列表语法适用的场景下,它会显得更繁琐。在点对表示法中,列表 ‘(1 2 3)’ 写作 ‘(1 . (2 . (3 . nil)))’。对于以 nil 结尾的常规列表,两种写法都可以使用,但列表语法通常更清晰、更方便。在打印列表时,只有当某个 cons 单元的 CDR 不是列表时,才会使用点对表示法。
下面是用方框图示说明点对表示法的例子,表示 (rose . violet):
--- ---
| | |--> violet
--- ---
|
|
--> rose
你可以将点对表示法与列表语法结合,方便地表示最终 CDR 不为 nil 的 cons 单元链。写法是:在列表最后一个元素后面加一个点,再跟上最后一个 cons 单元的 CDR。例如,(rose violet . buttercup) 等价于 (rose . (violet . buttercup))。
结构如下:
--- --- --- ---
| | |--> | | |--> buttercup
--- --- --- ---
| |
| |
--> rose --> violet
语法 (rose . violet . buttercup) 是非法的,因为它没有任何合理含义。如果强行解释,它会试图把 buttercup 放入一个 CDR 已经是 violet 的 cons 单元里。
列表 (rose violet) 等价于 (rose . (violet)),结构如下:
--- --- --- ---
| | |--> | | |--> nil
--- --- --- ---
| |
| |
--> rose --> violet
同理,三元素列表 (rose violet buttercup) 等价于 (rose . (violet . (buttercup)))。
结构如下:
--- --- --- --- --- ---
| | |--> | | |--> | | |--> nil
--- --- --- --- --- ---
| | |
| | |
--> rose --> violet --> buttercup
association list关联列表 简称 alist 是一种特殊构造的列表,它的元素都是 cons 单元。在每个元素中,CAR 被当作 key键,CDR 被当作 associated value关联值。(某些情况下,关联值会存放在 CDR 的 CAR 中。)关联列表常被当作栈来使用,因为在列表头部添加或删除关联项非常方便。
例如:
(setq alist-of-colors
'((rose . red) (lily . white) (buttercup . yellow)))
将变量 alist-of-colors 设置为一个包含三个元素的关联列表。在第一个元素中,rose 是键,red 是值。
关于关联列表的更多说明以及操作关联列表的函数,See 关联列表。关于另一种查找表(在处理大量键时速度快得多),See 哈希表。
array数组 由任意数量的槽位构成,用于存放或引用其他 Lisp 对象,这些槽位在内存中连续排列。访问数组中任意元素所花费的时间大致相同。与之相对,访问列表中的元素所需时间与元素在列表中的位置成正比。(列表末尾的元素比开头的元素访问耗时更长。)
Emacs 定义了四种数组:strings字符串、vectors向量、bool-vectors布尔向量和 char-tables字符表。
字符串是字符构成的数组,向量是可存放任意对象的数组。布尔向量只能存放 t 或 nil。这类数组的长度上限为最大定长整数,具体受系统架构限制和可用内存影响。字符表是稀疏数组,使用任意有效字符编码作为索引;它们可以存放任意对象。
数组的第一个元素下标为 0,第二个元素下标为 1,依此类推。这称为 zero-origin从零开始 索引。例如,一个包含四个元素的数组,下标为 0、1、2、3。最大可用下标值为数组长度减一。数组一旦创建,其长度就固定不变。
所有 Emacs Lisp 数组都是一维的。(大多数其他编程语言支持多维数组,但这并非必需;你可以用嵌套的一维数组达到同样效果。)每种数组都有自己的读取语法;详情见后续小节。
数组类型是序列类型的子集,它包含字符串类型、向量类型、布尔向量类型和字符表类型。
string字符串 是字符构成的数组。作为一款文本编辑器,Emacs 中字符串的用途非常广泛;例如用作 Lisp 符号的名称、展示给用户的提示信息,以及表示从缓冲区中提取的文本。Lisp 中的字符串是常量:对字符串求值,返回的仍是该字符串本身。
有关操作字符串的函数,See 字符串与字符。
字符串的读取语法是一对双引号,中间包含任意数量的字符,例如 "like this"。要在字符串中包含双引号,需在其前面加反斜杠;因此,"\"" 是一个只包含单个双引号的字符串。同理,要在字符串中包含反斜杠本身,需在前面再加一个反斜杠,例如:"this \\ is a single embedded backslash"。
由于字符串是字符数组,你可以使用字符的读取语法来指定字符串中的字符,但去掉开头的问号。这在字符串常量中包含那些不能表示自身的字符时非常有用。
因此,控制字符可以用以反斜杠开头的转义序列来表示;例如,"foo\r" 表示 ‘foo’ 后面跟一个回车符。其他控制字符的转义序列,See 基本字符语法。同样,你也可以使用控制字符的专用读取语法(see 控制字符语法),例如 "foo\^Ibar",它会在字符串中嵌入一个制表符。你还可以使用 通用转义语法 中描述的非-ASCII 字符转义序列,例如 "\N{LATIN SMALL LETTER A WITH GRAVE}" 和 "\u00e0"(但请注意 字符串中的非-ASCII 字符 一节中关于非-ASCII 字符的注意事项)。
换行符在字符串的读取语法中并不特殊:如果你在双引号之间直接换行,它会成为字符串中的一个字符。但转义换行符—— 即前面带 ‘\’ 的换行 ——不会成为字符串的一部分;也就是说,Lisp 读取器在读取字符串时会忽略转义换行。转义空格 ‘\ ’ 同样会被忽略。
"It is useful to include newlines
in documentation strings,
but the newline is \
ignored if escaped."
⇒ "It is useful to include newlines
in documentation strings,
but the newline is ignored if escaped."
在 Emacs 字符串中,非-ASCII 字符有两种文本表示方式:多字节(multibyte)和单字节(unibyte)(see Text Representations)。简单来说,单字节字符串存储原始字节,而多字节字符串存储人类可读的文本。单字节字符串中的每个字符都是一个字节,即其值在 0~255 之间。与之相对,多字节字符串中的每个字符值可以在 0~4194303 之间(see 字符类型)。在这两种表示中,大于 127 的字符都是非-ASCII 字符。
你可以在字符串常量中直接书写非-ASCII 字符。如果字符串常量从多字节源读取(例如多字节缓冲区或字符串、以多字节模式打开的文件),Emacs 会将每个非-ASCII 字符按多字节字符读取,并自动将该字符串设为多字节字符串。如果字符串常量从单字节源读取,Emacs 会将非-ASCII 字符按单字节读取,并将字符串设为单字节。
除了在多字节字符串中直接写字符,你也可以使用转义序列按字符编码来书写。关于转义序列的详情,See 通用转义语法。
如果在字符串常量中使用任何 Unicode 风格的转义序列 ‘\uNNNN’ 或 ‘\U00NNNNNN’ (即使是 ASCII 字符),Emacs 会自动将其视为多字节字符串。
你也可以在字符串常量中使用十六进制转义序列(‘\xn’)和八进制转义序列(‘\n’)。但请注意:如果字符串常量只包含八进制转义序列,或一两位的十六进制转义序列,且这些转义都表示单字节字符(即码点小于 256),同时字符串中没有其他直接书写的非-ASCII 字符或 Unicode 风格转义,Emacs 会自动将其视为单字节字符串。也就是说,它会把字符串中所有非-ASCII 字符都当作 8 位原始字节。
在十六进制和八进制转义序列中,转义的字符编码可以包含可变数量的数字,因此后续第一个不是有效十六进制 / 八进制数字的字符会终止转义。如果字符串的下一个字符可能被解析为十六进制或八进制数字,可以写 ‘\ ’ (反斜杠加空格)来终止转义序列。例如,‘\xe0\ ’ 表示一个字符:带重音的字母 ‘a’。字符串常量中的 ‘\ ’ 与反斜杠换行类似;它不会向字符串添加任何字符,但会终止前面的十六进制转义。
你可以在字符串常量中使用与字符字面量中相同的反斜杠转义序列(但不要使用字符常量开头的问号)。例如,你可以编写一个包含制表符和 C-a 这两个不可打印字符的字符串,它们之间用逗号和空格分隔,写法如下:"\t, \C-a"。有关字符的各种读取语法说明,See 字符类型 及其小节。
但是,并非所有能用反斜杠转义序列写出的字符在字符串中都合法。字符串只能容纳 ASCII 控制字符,并且字符串不区分 ASCII 控制字符的大小写。
严格来说,字符串不能存放元字符(meta 字符);但当字符串用作按键序列时,有一个特殊约定,可以在字符串中表示 ASCII 字符的元字符版本。如果你在字符串常量中使用 ‘\M-’ 语法表示元字符,会将该字符的
2**7
位(第 7 位) 置 1。如果该字符串用于 define-key 或 lookup-key,这个数值编码会被转换成对应的元字符。See 字符类型。
字符串不能存放带有 hyper、super 或 alt 修饰符的字符。
字符串除了存储其包含的字符本身,还可以为这些字符保存文本属性。这使得在字符串与缓冲区之间复制文本的程序,可以无需额外处理就同步复制文本的属性。关于文本属性的含义,See Text Properties。带有文本属性的字符串使用一种特殊的读取与打印语法:
#("characters" property-data...)
其中 property-data属性数据 由零个或多个元素组成,每三个为一组,格式如下:
beg end plist
beg 和 end 都是整数,它们共同指定字符串中的一段下标区间;plist 是该区间对应的属性列表。例如:
#("foo bar" 0 3 (face bold) 3 4 nil 4 7 (face italic))
表示一个文本内容为 ‘foo bar’ 的字符串,其中:前三个字符拥有 face 属性,值为 bold(粗体);最后三个字符拥有 face 属性,值为 italic(斜体)。(第四个字符没有任何文本属性,因此它的属性列表为 nil。实际上,属性列表为 nil 的区间不必显式写出,因为任何没有在任何区间中声明的字符,默认都不带属性。)
vector向量 是由任意类型元素构成的一维数组。访问向量中任意元素的时间是常数时间。(而在列表中,元素的访问时间与该元素到列表开头的距离成正比。)
向量的打印表示形式为:左方括号、元素、右方括号。这同时也是它的读取语法。与数字和字符串一样,向量在求值时被视为常量。
[1 "two" (three)] ; 包含三个元素的向量
⇒ [1 "two" (three)]
有关操作向量的函数,see 向量。
char-table字符表 是一种一维数组,其元素可以是任意类型,以字符编码作为下标索引。字符表具备一些额外特性,使其在需要为字符编码关联信息的场景中更加实用 —— 例如,字符表可以拥有一个父表以继承属性、设置默认值,以及少量用于特殊用途的额外槽位。字符表还可以为整个字符集指定统一的取值。
字符表的打印表示形式与向量类似,只是在开头多了一个 ‘#^’ 标记。1
有关操作字符表的专用函数,see 字符表。字符表的用途包括:
bool-vector布尔向量 是一种一维数组,其元素只能是 t(真)或 nil(假)。
布尔向量的打印表示形式与字符串类似,但开头会以 ‘#&’ 后跟长度值。紧随其后的字符串常量实际上以位图形式指定布尔向量的内容 —— 字符串中的每个字符包含 8 个比特位,对应布尔向量中接下来的 8 个元素(1 代表 t,0 代表 nil)。字符的最低有效位对应布尔向量中最小的索引位置。
(make-bool-vector 3 t)
⇒ #&3"^G"
(make-bool-vector 3 nil)
⇒ #&3"^@"
上述结果是合理的,因为 ‘C-g’ 二进制编码是 111,而 ‘C-@’ 是编码为 0 的字符。
如果布尔向量的长度不是 8 的整数倍,其打印表示会显示额外的元素,但这些额外元素实际上无任何意义。例如,在下面的示例中,两个布尔向量是相等的,因为仅前 3 个比特位会被实际使用:
(equal #&3"\377" #&3"\007")
⇒ t
哈希表是一种查找速度极快的查找表,在将键映射到对应的值这一点上,它有点类似关联列表(alist),但速度要快得多。哈希表的打印表示形式会标明它的属性和内容,如下所示:
(make-hash-table)
⇒ #s(hash-table)
有关哈希表的更多信息,see 哈希表。
Lisp 函数是可执行代码,与其他编程语言中的函数一样。与大多数语言不同,在 Lisp 中,函数本身也是 Lisp 对象。Lisp 中的非编译函数是一个 lambda 表达式:也就是一个列表,其第一个元素是符号 lambda(see Lambda 表达式)。
在大多数编程语言中,函数都必须有名字。而在 Lisp 中,函数本身并没有固有的名字。一个 lambda 表达式即使没有名字,也可以作为函数被调用;为强调这一点,我们也称其为anonymous function匿名函数(see 匿名函数)。Lisp 中的具名函数,只是一个在其函数槽中存有有效函数的符号(see 定义函数)。
大多数情况下,在 Lisp 程序的表达式里写下函数名,就会调用该函数。不过,你也可以在运行时构造或获取一个函数对象,然后使用原始函数 funcall 和 apply 来调用它。See 调用函数。
Lisp macro 是一种用户自定义的语法结构,用于扩展 Lisp 语言。它的表示形式与函数对象非常相似,但参数传递语义不同。Lisp 宏表现为一个列表,其第一个元素是符号 macro,CDR 部分是一个 Lisp 函数对象(包含 lambda 符号)。
Lisp 宏对象通常使用内置的 defmacro 宏来定义,但在 Emacs 看来,任何以 macro 开头的列表都是宏。有关如何编写宏的说明,see 宏。
警告:Lisp 宏与键盘宏(see 键盘宏)是完全不同的概念。当我们不加限定地使用 “宏" 一词时,指的都是 Lisp 宏,而非键盘宏。
primitive function原语函数 是可以从 Lisp 中调用,但由 C 语言编写的函数。原语函数也被称为 subrs 或 built-in functions内置函数。(“subr” 一词来源于 “subroutine”,即子程序。)大多数原语函数在调用时会对所有参数求值。不对全部参数求值的原语函数称为 special form特殊形式(see 特殊形式)。
对于函数调用者来说,该函数是否为原语函数并不重要。但如果你尝试用 Lisp 函数重定义一个原语函数,情况就不一样了。原因在于:原语函数可能会被 C 代码直接调用。从 Lisp 中调用重定义后的函数会使用新定义,但从 C 代码中的调用仍可能使用内置的原定义。因此,我们不建议重定义原语函数。
术语 function函数 泛指所有 Emacs 函数,无论它是用 Lisp 还是 C 编写的。关于 Lisp 编写的函数,see 函数类型。
原语函数没有可读语法,打印时会以井号尖括号形式显示子程序名称。
(symbol-function 'car) ; 访问符号的函数单元。即获取符号绑定的函数 ⇒ #<subr car> ; 输出:#<subr car> (subrp (symbol-function 'car)) ; 这是一个原始函数吗? ⇒ t ; 是。
Closures闭包 是将函数定义转化为函数值时生成的函数对象。闭包既用于字节编译的 Lisp 函数,也用于解释执行的 Lisp 函数。闭包可以通过对 Lisp 代码进行字节编译(see 字节编译)产生,也可以直接对未编译的 lambda 表达式求值得到,后者会成为一个解释型函数。在内部实现上,闭包与向量非常相似;但在函数调用中,求值器会对这种数据类型做特殊处理。See 闭包函数对象。
字节码函数对象的打印表示和可读语法与向量类似,只是在左方括号 ‘[’ 前多一个 ‘#’。为方便人类阅读时,它会以一种特殊列表形式打印,在左括号 ‘(’ 前多一个 ‘#f’。
record记录 与 vector 非常相似。不过,第一个元素用于存放其类型,即 type-of 函数返回的类型。记录的作用是让程序员可以创建不属于 Emacs 内置类型的自定义类型对象。
有关操作记录的函数,see 记录。
type descriptor类型描述符 是一种用于存放类型相关信息的记录。该记录的第一个槽位必须是表示该类型名称的符号,type-of 正是依靠这一点来返回 record 对象的类型。Emacs 本身不会使用类型描述符的其他槽位,这些槽位可自由用于 Lisp 扩展。
cl-structure-class 的任意实例都是类型描述符的一个例子。
类型说明符是表示一种类型的表达式。类型代表一组可能的取值。类型说明符可分为基本类型与复合类型。
类型说明符有多种用途,包括:通过声明来为函数接口提供文档(see declare 形式)、指定结构体槽位类型(see Structures in Common Lisp Extensions for GNU Emacs Lisp)、使用 cl-the 进行类型检查(see Declarations in Common Lisp Extensions for GNU Emacs Lisp),以及帮助本地编译器(see Lisp 本地代码编译)优化代码生成和推断函数签名。
基本类型说明符是基础类型(即不由其他类型说明符组合而成)。
内置的基本类型(如 integer整数、float浮点数、string字符串等)列于 Emacs Lisp 对象的类型层次 中。
复合类型用于通过组合或修改简单类型,定义更复杂或更精确的类型规范。
复合类型说明符列表:
(or type-1 … type-n)or 类型说明符表示一个类型,它满足给定类型中的至少一种。
(and type-1 … type-n)类似地,and 类型说明符表示一个类型,它满足所有给定类型。
(not type)not 类型说明符表示除指定类型外的任意类型。
(member value-1 … value-n)member 类型说明符用于定义一个只包含显式列出的值的类型。
(function (arg-1-type … arg-n-type) return-type) ¶function 类型说明符用于描述函数的参数类型和返回值类型。参数类型中可以穿插 &optional 和 &rest 符号,以匹配函数的参数形式(see 参数列表的特性)。
下面的类型说明符表示一个函数:第一个参数为 symbol符号 类型,第二个为可选 float浮点数 类型,返回值为 integer整数 类型:
(function (symbol &optional float) integer)
(integer lower-bound upper-bound)integer整数 类型说明符也可以作为复合类型说明符,通过指定范围来定义整数的子集。这可以精确控制哪些整数对给定类型有效。
lower-bound 是范围中的最小整数,upper-bound 是最大整数。你可以用 * 代替下界或上界,表示无限制。
下面表示从 -10 到 10 的所有整数:
(integer -10 10)
下面表示单个值 10:
(integer 10 10)
下面表示从负无穷到 10 的所有整数:
(integer * 10)
autoload object自动加载对象 是一个以符号 autoload 为第一个元素的列表。它作为符号的函数定义被存储,充当真实函数定义的占位符。自动加载对象表明:真正的定义位于某个 Lisp 代码文件中,应在需要时加载该文件。它包含文件名,以及关于真实定义的其他一些信息。
文件加载完成后,该符号会拥有一个不再是自动加载对象的新函数定义。之后调用新定义,就像它一开始就存在一样。从用户角度看,函数调用正常工作,使用的是加载后文件中的函数定义。
自动加载对象通常由函数 autoload 创建,并将该对象存入符号的函数槽中。更多细节 see 自动加载。
finalizer object终结器对象 用于帮助 Lisp 代码在不再需要某些对象时进行清理工作。一个终结器会持有一个 Lisp 函数对象。当某次垃圾回收完成后,若该终结器对象变为不可达,Emacs 就会调用与该终结器关联的函数。 在判断一个终结器是否可达时,Emacs 不计入来自其他终结器自身的引用,这让你在使用终结器时不必担心意外持有对被终结对象的引用。
终结器中出现的错误会被打印到 *Messages* 缓冲区。对于同一个终结器对象,其关联函数只会被执行一次,即便该函数执行失败。
创建一个会运行 function 的终结器。当返回的终结器对象在垃圾回收后变为不可达时,function 将会被调用。 如果该终结器对象仅通过其他终结器的引用才可达,那么在判断是否运行 function 时,它将被视为不可达。每个终结器对象只会执行一次对应的 funtion。
上一节介绍的类型用于通用编程,其中大多数在各 Lisp 方言中都很常见。Emacs Lisp 还提供了若干专门用于编辑操作的额外数据类型。
buffer缓冲区 是一个用于存放可编辑文本的对象(see 缓冲区)。大多数缓冲区用来存放磁盘文件的内容以便编辑(see 文件),但也有一部分缓冲区用于其他用途。大多数缓冲区会展示给用户,并在某个时刻显示在窗口中(see Windows),但缓冲区并非必须显示在任何窗口里。 每个缓冲区都有一个指定位置,称为 point光标位置(see Positions);大多数编辑命令都作用于当前缓冲区中光标附近的内容。在任意时刻,都有且仅有一个 current buffer当前缓冲区。
缓冲区的内容与字符串很像,但在 Emacs Lisp 中,缓冲区和字符串的用法不同,可用的操作也不一样。例如,你可以高效地向已有缓冲区插入文本,直接修改缓冲区内容;而向字符串插入文本则需要拼接子串,结果会生成一个全新的字符串对象。
许多标准 Emacs 函数都会操作或检测当前缓冲区中的字符;本手册有专门一章用来描述这些函数(see Text)。
每个缓冲区还关联着若干其他数据结构:
局部按键映射和变量列表中的项会分别覆盖全局的绑定或取值。它们用于在不同缓冲区中定制程序行为,而无需真正修改程序本身。
缓冲区可以是 indirect间接缓冲区,即它与另一个缓冲区共享文本,但展示方式不同。See Indirect Buffers。
缓冲区没有可读语法。打印时会以井号尖括号形式显示缓冲区名称。
(current-buffer)
⇒ #<buffer objects.texi>
marker标记 用于标识特定缓冲区中的一个位置。因此,标记包含两个部分:一个指向缓冲区,一个指向位置。 当缓冲区中的文本发生变化时,标记对应的位置值会自动调整,以保证标记始终指向缓冲区中相同的两个字符之间。
标记没有可读语法。打印时会以井号尖括号形式显示当前字符位置和缓冲区名称。
(point-marker)
⇒ #<marker at 10779 in objects.texi>
有关如何检测、创建、复制和移动标记的信息,see Markers。
window窗口 描述了 Emacs 用来显示缓冲区的屏幕区域。每个活动窗口(see Basic Concepts of Emacs Windows)都关联一个缓冲区,缓冲区的内容会显示在该窗口中。与之相对,同一个缓冲区可以显示在一个窗口、不显示在任何窗口,或同时显示在多个窗口中。窗口在屏幕上被组织到各个框架内;每个窗口有且只属于一个框架。See 框架类型。
尽管可以同时存在多个窗口,但在任意时刻都有一个窗口被指定为 selected window选中窗口(see Selecting Windows)。当 Emacs 等待输入命令时,光标(通常)就显示在这个窗口里。选中窗口一般会显示当前缓冲区(see The Current Buffer),但并非一定如此。
窗口没有可读语法。打印时会以井号尖括号形式显示窗口编号和所显示的缓冲区名称。窗口编号的作用是唯一标识窗口,因为同一个窗口显示的缓冲区可能会频繁变化。
(selected-window)
⇒ #<window 1 on objects.texi>
有关操作窗口的函数说明,see Windows。
fram框架 是一块包含一个或多个 Emacs 窗口的屏幕区域;我们也用 “frame(框架)” 一词表示 Emacs 用来指代这块屏幕区域的 Lisp 对象。
框架没有可读语法。打印时会以井号尖括号形式显示框架标题及其内存地址(用于唯一标识该框架)。
(selected-frame)
⇒ #<frame [email protected] 0xdac80>
有关操作框架的函数说明,see Frames。
terminal终端 是一种能够显示一个或多个 Emacs 框架的设备(see 框架类型)。
终端没有可读语法。打印时会以井号尖括号形式显示终端序号及其 TTY 设备文件名。
(get-device-terminal nil)
⇒ #<terminal 1 on /dev/tty>
window configuration窗口配置 用于保存一个框架内所有窗口的位置、大小和显示内容等信息,以便之后恢复出相同的窗口布局。
窗口配置没有可读语法,其打印形式为 ‘#<window-configuration>’。有关窗口配置的相关函数说明,see Window Configurations。
frame configuration框架配置 用于保存所有框架中窗口的位置、大小和内容等信息。它不是基本类型,实际上是一个列表:其 CAR 为 frame-configuration,CDR 为一个关联列表(alist)。关联列表中的每个元素描述一个框架,该框架作为元素的 CAR 存在。
有关框架配置的相关函数说明,see Frame Configurations。
process 一词通常指正在运行的程序。Emacs 自身就在这样一个进程中运行。但在 Emacs Lisp 中,进程是一个 Lisp 对象,用来表示由 Emacs 进程创建的子进程。 诸如 shell、GDB、ftp、编译器等程序,在 Emacs 的子进程中运行,可以扩展 Emacs 的功能。Emacs 子进程从 Emacs 接收文本输入,并将文本输出返回给 Emacs 做进一步处理。Emacs 还可以向子进程发送信号。
进程对象没有可读语法。打印时会以井号尖括号形式显示进程名:
(process-list)
⇒ (#<process shell>)
有关创建、删除、查询进程、向进程发送输入或信号、接收进程输出等函数的信息,see Processes。
Emacs 中的 thread线程 代表一条独立的 Emacs Lisp 执行流。它运行自己的 Lisp 程序,拥有独立的当前缓冲区,并且可以绑定专属子进程 —— 即输出只能由该线程接收的子进程。See Threads。
线程对象没有可读语法,打印时以井号尖括号形式显示线程名(若已命名)或内存地址:
(all-threads)
⇒ (#<thread 0176fc40>)
mutex互斥锁 是一种独占锁,线程可以获取和释放它,以实现线程间的同步。See Mutexes。
互斥锁对象没有可读语法。它们以井号尖括号形式打印,显示互斥锁名称(如果已命名)或其内存地址:
(make-mutex "my-mutex")
⇒ #<mutex my-mutex>
(make-mutex)
⇒ #<mutex 01c7e4e0>
condition variable条件变量 是一种用于比互斥锁更复杂的线程同步机制。一个线程可以在某个条件变量上等待,直到其他线程对该条件发出通知后才被唤醒。
条件变量对象没有可读语法。它们以井号尖括号形式打印,显示条件变量名称(如果已命名)或其内存地址:
(make-condition-variable (make-mutex))
⇒ #<condvar 01c45ae8>
stream流 是一种可用作字符源或字符接收端的对象 — 既可以提供字符用于输入,也可以接收字符用于输出。许多不同类型都可以这样使用:标记、缓冲区、字符串和函数。最常见的情况是,输入流(字符源)从键盘、缓冲区或文件中获取字符,输出流(字符接收端)将字符发送到缓冲区(如 *Help* 缓冲区)或回显区。
对象 nil 除了其他含义外,也可以用作流。它代表变量 standard-input 或 standard-output 的值。此外,对象 t 作为流时,表示使用迷你缓冲区(see 迷你缓冲区)进行输入,或在回显区(see The Echo Area)进行输出。
流没有专门的打印表示或可读语法,会按照其所属的基本类型进行打印。
有关流相关函数(包括解析和打印函数)的说明,see Lisp 对象的读取与打印。
keymap按键映射 将用户输入的按键映射到对应的命令。这种映射控制着用户命令输入的执行方式。按键映射实际上是一个列表,其 CAR 为符号 keymap。
有关创建按键映射、处理前缀键、局部与全局按键映射,以及修改按键绑定的信息,see 按键映射。
overlay覆盖层 用于指定应用于缓冲区某一部分的属性。每个覆盖层作用于缓冲区中一个指定的区间,并包含一个属性列表(元素为属性名与属性值交替出现的列表)。覆盖层属性用于临时以不同的显示样式展示缓冲区的部分内容。覆盖层没有可读语法,打印时以井号尖括号形式显示缓冲区名称和位置区间。
有关如何创建和使用覆盖层的信息,see Overlays。
font字体 用于指定在图形终端上如何显示文本。实际上存在三种独立的字体类型:font objects字体对象、font specs字体规格和 font entities字体实体,每种类型的属性略有不同。它们都没有可读语法,打印形式分别为:‘#<font-object>’、‘#<font-spec>’ 和 ‘#<font-entity>’。 有关这些 Lisp 对象的说明,see Low-Level Font Representation。
xwidget组件部件 是一种特殊的显示元素,例如网页浏览器,可嵌入到缓冲区内部。每个显示 xwidget 的窗口还会拥有一个 xwidget 视图,在 X-Windows 下,该视图对应一个用于显示此部件的独立 X 窗口。
这两种对象都不具备可读语法;它们的打印形式分别形如 ‘#<xwidget>’ 和 ‘#<xwidget-view>’。有关 xwidget 的更详细说明,see Embedded Native Widgets。
要在一组 Lisp 对象中表示共享或循环结构,你可以使用读取器构造符 ‘#n=’ 和 ‘#n#’。
在一个对象前使用 #n= 可为其添加标签,以便后续引用;之后,你可以在其他位置使用 #n# 来引用同一个对象。其中 n 是某个整数。例如,以下写法可创建一个列表,使其第一个元素同时作为第三个元素出现:
(#1=(a) b #1#)
这与如下普通语法不同:
((a) b (a))
后者生成的列表中,第一个和第三个元素看起来相同,但并非同一个 Lisp 对象。以下代码可体现这种差异:
(prog1 nil
(setq x '(#1=(a) b #1#)))
(eq (nth 0 x) (nth 2 x))
⇒ t
(setq x '((a) b (a)))
(eq (nth 0 x) (nth 2 x))
⇒ nil
你也可以使用相同的语法创建循环结构(即对象自身包含自身作为元素)。示例如下:
#1=(a #1#)
这会创建一个列表,其第二个元素就是该列表本身。可通过以下方式验证其效果:
(prog1 nil
(setq x '#1=(a #1#)))
(eq x (cadr x))
⇒ t
若将变量 print-circle 绑定为非-nil 值,Lisp 打印器会生成此类语法,以记录 Lisp 对象中的循环和共享结构。See 影响输出的变量。
Emacs Lisp 解释器本身不会在函数调用时,对传递给函数的实际参数执行类型检查。这是因为 Lisp 中的函数参数不像其他编程语言那样有声明的数据类型,因此解释器无法完成这类检查。故而,需要由各个函数自行检验每个实际参数是否属于该函数可处理的类型。
所有内置函数都会在适当时机检查其实际参数的类型;若参数类型错误,会触发 wrong-type-argument 错误。例如,向 + 函数传入其无法处理的参数时,会出现如下情况:
(+ 2 'a)
error→ Wrong type argument: number-or-marker-p, a
若希望程序根据不同类型执行不同逻辑,必须显式进行类型检查。检查对象类型最常用的方式是调用 type predicate类型谓词 函数。Emacs 为每种类型都提供了对应的类型谓词,同时也包含一些针对类型组合的谓词。
类型谓词函数接收一个参数:若该参数属于对应类型,则返回 t,否则返回 nil。遵循 Lisp 谓词函数的通用约定,大多数类型谓词的名称以 ‘p’ 结尾。
以下示例使用谓词 listp 检查列表类型、symbolp 检查符号类型:
(defun add-on (x)
(cond ((symbolp x)
;; If X is a symbol, put it on LIST.
(setq list (cons x list)))
((listp x)
;; If X is a list, add its elements to LIST.
(setq list (append x list)))
(t
;; We handle only symbols and lists.
(error "Invalid argument %s in add-on" x))))
下表按字母顺序列出了预定义的类型谓词,并标注了进一步说明的引用位置:
atomSee atom.
arraypSee arrayp.
bignumpSee bignump.
bool-vector-pSee bool-vector-p.
booleanpSee booleanp.
bufferpSee bufferp.
byte-code-function-pSee byte-code-function-p.
case-table-pSee case-table-p.
char-or-string-pSee char-or-string-p.
char-table-pSee char-table-p.
closurepSee closurep.
commandpSee commandp.
compiled-function-pSee compiled-function-p.
condition-variable-pSee condition-variable-p.
conspSee consp.
custom-variable-pSee custom-variable-p.
fixnumpSee fixnump.
floatpSee floatp.
fontpframe-configuration-pframe-live-pSee frame-live-p.
framepSee framep.
functionpSee functionp.
hash-table-pSee hash-table-p.
integer-or-marker-pSee integer-or-marker-p.
integerpSee integerp.
interpreted-function-pkeymappSee keymapp.
keywordpSee 永不改变的变量.
listpSee listp.
markerpSee markerp.
mutexpSee mutexp.
nlistpSee nlistp.
number-or-marker-pSee number-or-marker-p.
numberpSee numberp.
obarraypSee obarrayp.
overlaypSee overlayp.
processpSee processp.
recordpSee recordp.
sequencepSee sequencep.
string-or-null-pSee string-or-null-p.
stringpSee stringp.
subrpSee subrp.
symbolpSee symbolp.
syntax-table-pSee syntax-table-p.
threadpSee threadp.
vectorpSee vectorp.
wholenumpSee wholenump.
window-configuration-pwindow-live-pSee window-live-p.
windowpSee windowp.
检查对象类型最通用的方式是调用 type-of 函数。需注意,每个对象仅属于一种原始类型; type-of 会返回该对象所属的原始类型(see Lisp 数据类型)。但 type-of 无法识别非原始类型,因此在大多数情况下,使用类型谓词比 type-of 更合适。
该函数返回一个符号,代表 object 的原始类型。返回值为以下符号之一:
bool-vector,
buffer, char-table, compiled-function,
condition-variable, cons, finalizer,
float, font-entity, font-object,
font-spec, frame, hash-table, integer,
marker, mutex, obarray, overlay, process,
string, subr, symbol, thread,
vector, window, or window-configuration。
但如果 object 是记录(record),则返回其第一个槽位指定的类型;记录。
(type-of 1)
⇒ integer
(type-of 'nil)
⇒ symbol
(type-of '()) ; () is nil.
⇒ symbol
(type-of '(x))
⇒ cons
(type-of (record 'foo))
⇒ foo
该函数返回一个符号,代表 object 的类型。其行为通常与 type-of 一致,但会保证返回尽可能精确的类型 —— 这也意味着,它返回的具体类型可能随 Emacs 版本变化。因此,原则上不应将其返回值与固定的类型集合做比较。
(cl-type-of 1)
⇒ fixnum
(cl-type-of 'nil)
⇒ null
(cl-type-of (record 'foo))
⇒ foo
本节介绍用于检验两个对象是否相等的函数。另有一些函数用于检验特定类型对象(如strings字符串)的内容是否相等,相关谓词可参见对应数据类型的说明章节。
若 object1 和 object2 是同一个对象,该函数返回 t,否则返回 nil。
如果 object1 和 object2 是名称相同的符号,它们通常是同一个对象 —— 但存在例外情况(创建与编入符号)。对于其他非数值类型(如列表、向量、字符串),即便内容或元素完全相同,它们也不一定满足 eq 相等:只有当它们是同一个对象时才会 eq 相等,这意味着修改其中一个的内容,另一个的内容也会同步发生相同的变化。
如果 object1 和 object2 是类型或数值不同的数字,那么它们不可能是同一个对象,eq 返回 nil。如果它们是值相同的定点数(fixnum),那么它们是同一个对象,eq 返回 t。如果它们是分别计算得到,但恰好值相同且属于非定点数类型,那么它们可能是同一个对象,也可能不是;eq 会返回 t 或 nil,取决于 Lisp 解释器创建的是一个对象还是两个对象。
如果 object1 或 object2 是带位置信息的符号,当 symbols-with-pos-enabled 为非-nil 时,eq 会将其视为无附加信息的原始符号(see 带位置信息的符号)。
(eq 'foo 'foo)
⇒ t
(eq ?A ?A)
⇒ t
(eq 3.0 3.0)
⇒ t or nil
;; 数值相等的浮点数可能是、也可能不是同一个对象
(eq (make-string 3 ?A) (make-string 3 ?A))
⇒ nil
(eq "asdf" "asdf")
⇒ t or nil
;; 内容相等的字符串常量可能是、也可能不是同一个对象
(eq '(1 (2 (3))) '(1 (2 (3))))
⇒ nil
(setq foo '(1 (2 (3))))
⇒ (1 (2 (3)))
(eq foo foo)
⇒ t
(eq foo '(1 (2 (3))))
⇒ nil
(eq [(1 2) 3] [(1 2) 3])
⇒ nil
(eq (point-marker) (point-marker))
⇒ nil
make-symbol 函数会返回一个未存入(uninterned)的符号,它与直接书写符号名得到的符号是不同的对象。即便名称相同,不同的符号也不会是 eq 的。See 创建与编入符号。
(eq (make-symbol "foo") 'foo)
⇒ nil
Emacs Lisp 字节编译器可能会把完全相同的字面量对象(比如字面字符串)合并成指向同一个对象的引用。这会导致一个结果:经过字节编译的代码里这些对象用 eq 比较会相等,而同样代码在解释执行时却不相等。
因此,你的代码永远不应该依赖“内容相同的字面量对象用 eq 比较是否相等” 这一点,而应该使用下文介绍的、用于比较对象内容的函数,例如 equal。
同理,你的代码不应该修改字面量对象(比如给字面字符串添加文本属性),因为如果字节编译器把它们合并了,这样的修改可能会影响到其他内容相同的字面量对象。
如果 object1 和 object2 的组成部分相等,该函数返回 t,否则返回 nil。eq 用于判断参数是否为同一个对象,而 equal 会深入不同对象的内部,检查它们的元素或内容是否相同。
因此:如果两个对象满足 eq,则一定满足 equal;但反过来不一定成立。
(equal 'foo 'foo)
⇒ t
(equal 456 456)
⇒ t
(equal "asdf" "asdf")
⇒ t
(eq "asdf" "asdf")
⇒ nil
(equal '(1 (2 (3))) '(1 (2 (3))))
⇒ t
(eq '(1 (2 (3))) '(1 (2 (3))))
⇒ nil
(equal [(1 2) 3] [(1 2) 3])
⇒ t
(eq [(1 2) 3] [(1 2) 3])
⇒ nil
(equal (point-marker) (point-marker))
⇒ t
(eq (point-marker) (point-marker))
⇒ nil
equal 函数按值比较字符串和布尔向量。数值则使用 eql,同时比较类型和数值。list(列表)、cons 单元、vector(向量)、record(记录)、marker(标记)、char-table(字符表)、font object(字体对象)以及function object(函数对象)(闭包)2 会通过对其组成部分递归调用 equal 来进行比较。
字符串的比较区分大小写,但不考虑文本属性 — 它只比较字符串里的字符。See Text Properties。若要同时比较文本属性,请使用 equal-including-properties。出于技术原因,单字节字符串与多字节字符串 equal 相等的充要条件是:它们包含完全相同的字符编码序列,并且所有编码都在 0~127(ASCII)范围内。
(equal "asdf" "ASDF")
⇒ nil
如果 object1 或 object2 包含带位置信息的符号,当 symbols-with-pos-enabled 为非-nil 时,equal 会将它们当作普通裸符号处理。否则,equal 会通过比较各个组成部分来判断两个带位置信息的符号是否相等。See 带位置信息的符号。
其他对象只有在满足 eq 时,才会被认为是 equal。例如,两个不同的缓冲区(buffer)即使文本内容相同,也永远不会被视为相等。
equal 的相等性是递归定义的;例如,给定两个 cons 单元 x 和 y,(equal x y) 返回 t,当且仅当下面两个表达式都返回 t:
(equal (car x) (car y)) (equal (cdr x) (cdr y))
因此,比较循环列表可能会引发深层递归并导致报错,还可能出现违反直觉的行为 —— 例如 (equal a b) 返回 t,而 (equal b a) 却触发错误。
该函数在所有场景下的行为均与 equal 一致,但额外要求:若两个字符串要判定为相等,必须具备完全相同的文本属性。
(equal "asdf" (propertize "asdf" 'asdf t))
⇒ t
(equal-including-properties "asdf"
(propertize "asdf" 'asdf t))
⇒ nil
有些 Lisp 对象永远不应该被修改。例如,Lisp 表达式 "aaa" 会生成一个字符串,但你不应该修改它的内容。还有一些对象本身就无法被修改;例如,虽然你可以通过计算得到一个新的数字,但 Lisp 不提供任何操作来修改一个已存在数字的值。
另一些 Lisp 对象是 mutable可变的:通过带有副作用的破坏性操作来修改它们的值是安全的。例如,一个已存在的标记(marker)可以通过移动到其他位置来被修改
虽然数字永远不可变、所有标记都是可变的,但某些类型既有可变成员,也有不可变成员。这些类型包括:点对(cons)、向量和字符串。例如:尽管 "cons" 和 (symbol-name 'cons) 都生成不应该被修改的字符串,但 (copy-sequence "cons") 和 (make-string 3 ?a) 都会生成可变字符串,后续可以通过 aset 来修改。
如果一个可变对象成为了被 eval 求值的表达式的一部分,它就不再是可变的。示例:
(let* ((x (list 0.5))
(y (eval (list 'quote x))))
(setcar x 1.5) ;; 程序不应该这么做
y)
虽然列表 (0.5) 在创建时是可变的,但因为它被传给了 eval,就不应该再用 setcar 修改。反向情况不会发生:本就不应该被修改的对象,之后永远不会变成可变对象。
如果程序试图修改不应该被修改的对象,其行为是未定义的:Lisp 解释器可能会抛出错误,也可能崩溃,或以其他不可预测的方式运行。3
当相似的常量作为程序的一部分出现时,Lisp 解释器可能会为了节省时间或空间,复用已有的常量或其组成部分。例如:(eq "abc" "abc") 在解释器只创建一个字符串字面量 "abc" 实例时返回 t,创建两个实例时返回 nil。编写 Lisp 程序时,应保证无论是否启用这类优化,程序都能正常运行。
Lisp 对象类型按层次结构组织,这意味着类型可以从其他类型派生而来。派生自类型 A 的类型 B 的对象,会继承类型 A 的所有特性。这也表示:每个类型 B 的对象,同时也是它所派生自的类型 A 的对象。
所有类型都派生自类型 t。
用户可以通过 defclass 或 cl-defstruct 定义新类型。
原始类型的 Lisp 类型层次结构可表示如下:
例如,list列表 类型派生自 sequence序列 类型,而序列类型本身又派生自 t。
GNU Emacs 支持两种数值数据类型:integers整数 和 floating-point numbers浮点数。整数是没有小数部分的数,例如 −3、0、7、13 和 511。浮点数是带有小数部分的数,例如 −4.5、0.0 和 2.71828。它们也可以用指数形式表示:‘1.5e2’ 等价于 ‘150.0’;其中 ‘e2’ 表示 10 的 2 次方,再与 1.5 相乘。 整数运算结果是精确的。浮点数运算通常会包含舍入误差,因为数值的精度是固定有限的。
Lisp 读取器将整数解析为非空十进制数字序列,可带可选的正负号,以及可选的末尾句点。
1 ; The integer 1. 1. ; The integer 1. +1 ; Also the integer 1. -1 ; The integer −1. 0 ; The integer 0. -0 ; The integer 0.
非十进制进制的整数语法为:以 ‘#’ 开头,后跟进制标识,再跟一位或多位数字。进制标识:‘b’ 为二进制、‘o’ 为八进制、‘x’ 为十六进制、‘radixr’ 为自定义 radix 进制。因此,‘#binteger’ 按二进制读取 integer,‘#radixrinteger’ 按 radix 进制读取 integer。radix 的值合法进制范围:2~36。合法数字:从 ‘0’–‘9’、‘A’–‘Z’ 中取前 radix 个字符。字母大小写不敏感,不能带符号或末尾句点。 示例:
#b101100 ⇒ 44 #o54 ⇒ 44 #x2c ⇒ 44 #24r1k ⇒ 44
要理解各类整数相关函数,尤其是按位运算符(see 整数的按位运算),通常需要以二进制形式看待数值。
十进制整数 5 的二进制形式:
...000101
(省略号 ‘…’ 表示理论上无限多的前导相同位,这里是无限个 0。后续示例也会使用此 ‘…’ 写法。)
整数 −1 的二进制形式:
...111111
−1 表示为全 1,这称为 two’s complement二进制补码 表示法。
从 −1 减去 4 得到负整数 −5。十进制 4 的二进制是 100,因此 −5 的二进制为:
...111011
本章介绍的许多函数可以接受标记(marker) 代替数值作为参数。(See Markers。)由于这类函数的实参可以是数值或标记,我们常将参数命名为 number-or-marker。当参数是标记时,使用其位置值,忽略其所在缓冲区。
在 Emacs Lisp 中,文本字符用整数表示。0 到 (max-char)(包含)之间的任意整数都可作为合法字符。See Character Codes。
Emacs Lisp 的整数不受机器字长限制。但底层实现上,整数分为两类:较小的整数为 fixnums定长数、较大的整数为 bignum大数。
通常 Emacs Lisp 代码不应依赖整数是 fixnum 还是 bignum。但旧版 Emacs 只支持 fixnum,部分函数仍只接受 fixnum,旧代码在使用 bignum 时可能出错。例如:旧代码可用 eq 判断整数相等;但引入 bignum 后,应使用 eql 或 = 比较整数。
bignum 的取值范围受以下因素限制:主存大小、机器特性(如表示 bignum 指数的字长)、integer-width 变量。
其限制通常比 fixnum 宽松得多。bignum 与 fixnum 不会数值相等:在 fixnum 范围内的整数,Emacs 永远用 fixnum 表示,而非 bignum。
fixnum 的范围取决于机器。最小范围:−536,870,912 ~ 536,870,911(30 位,即 −2**29 到 2**29 − 1), 但很多机器支持更宽范围。
该变量的值是 Emacs Lisp 能处理的最大 “samll(小整数)”。典型值: 32 位平台为 2**29 − 1 和64 位平台为 2**61 − 1
该变量的值是 Emacs Lisp 能处理的最小 “samll(小整数)”,为负数。典型值: 32 位平台为 −2**29 和64 位平台为 −2**61
该变量为非负整数,用于控制:当计算出超大整数时,Emacs 是否抛出范围错误。绝对值小于 2**n, (n 为该变量值)的整数不会抛出范围错误。尝试创建更大的整数时通常会报错,除非能低成本生成。将此变量设得很大,在生成超大整数时可能代价很高。
浮点数适用于表示非整数数值。其取值范围与你所用机器上 C 语言的 double 数据类型一致。在几乎所有 Emacs 支持的计算机上,浮点数均采用 IEEE binary64(双精度)浮点格式—— 该格式由 IEEE Std
754-2019 标准化,David Goldberg 的论文 “What Every Computer Scientist Should Know About Floating-Point Arithmetic” 也对其有深入探讨。现代平台上的浮点运算基本遵循 IEEE-754 标准,但部分系统(尤其是 32 位 x86 架构)的运算结果可能无法保证正确舍入。
在某些老旧计算机系统上,Emacs 可能不使用 IEEE 浮点数。我们已知有一个这样的系统:运行 NetBSD 并使用 GCC 10.4.0 的 VAX 计算机,Emacs 可以正常运行,但不遵循 IEEE-754,而是改用 VAX 的 ‘D_Floating’ 格式。基于 IBM System/370 的大型机及其 XL/C 编译器也支持十六进制浮点数格式,但 Emacs 尚未在这类配置下编译构建过。
浮点数的读取语法要求必须包含小数点、指数,或两者同时具备。数值及其指数前可添加可选符号(‘+’ 或 ‘-’)。例如,‘1500.0’、‘+15e2’、‘15.0e+2’、‘+1500000e-3’ 和 ‘.15e4’ 是表示数值 1500 的五种浮点数写法,它们完全等价。与 Common Lisp 一致,Emacs Lisp 规定:对于不含指数的浮点数,小数点后必须至少有一位数字;因此 ‘1500.’ 会被解析为整数,而非浮点数。
在 = 等数值比较操作中,Emacs Lisp 将 -0.0 视为与普通零在数值上相等。这一行为遵循 IEEE 浮点标准 —— 该标准规定,即便其他操作可区分 -0.0 和 0.0,二者在数值层面仍相等。
IEEE 浮点标准支持将正无穷和负无穷作为浮点值,还定义了一类名为 NaN (即 “not a number非数值”)的值;当数值函数无合法计算结果时,会返回此类值。例如,(/ 0.0 0.0) 会返回 NaN。NaN 在数值上永不等于任何值,甚至不等于其自身。NaN 包含符号和尾数,若两个 NaN 的符号与尾数均一致,非数值函数会将它们判定为相等。NaN 的尾数及其字符串表示形式均依赖于具体机器。
当涉及 NaN 和带符号零(0.0 或 −0.0)时,eql、equal、sxhash-eql、sxhash-equal 和 gethash 这类非数值函数判断的是值是否不可区分,而非数值上是否相等。例如:当 x 和 y 是同一个 NaN 时,(equal x y) 返回 t,而 (= x y) 进行数值比较,返回 nil;反之,(equal 0.0 -0.0) 返回 nil,而 (= 0.0 -0.0) 返回 t。
以下是这些特殊浮点值的读取语法:
无穷大:‘1.0e+INF’ 和 ‘-1.0e+INF’
非数值(NaN):‘0.0e+NaN’ 和 ‘-0.0e+NaN’
在不支持 IEEE 浮点运算的老旧系统中,无穷大和 NaN 不可用。例如在 1980 年左右的 VAX 机器上,Lisp 会将 ‘1.0e+INF’ 解析为一个很大但有限的浮点数,将 ‘0.0e+NaN’ 解析为其他非数值型 Lisp 对象,若将其用于数值运算会触发错误。
以下是专门用于处理浮点数的函数:
该谓词函数的返回值规则:若浮点类型参数 x 是 NaN,返回 t;否则返回 nil。
该函数返回一个 cons 单元格 (s . e),其中 s 和 e 分别是浮点数 x 的尾数(significand)和指数(exponent)。
若 x 是有限值:s 是介于 0.5(包含)和 1.0(不包含)之间的浮点数,e 是整数,且满足 x = s * 2**e。 若 x 是 0 或无穷大:s 与 x 相等。 若 x 是 NaN:s 也为 NaN。 若 x 是 0,e 为 0。
给定数值型尾数 s 和整数型指数 e,该函数返回浮点数结果为 s * 2**e。
该函数将 x2 的符号复制到 x1 的数值上,并返回结果。x1 和 x2 必须均为浮点类型。
该函数返回 x 的二进制指数。更精确地说: 若 x 是有限非零值,返回值为 \(|x|\) 以 2 为底的对数,向下取整为整数; 若 x 是 0 或无穷大,返回值为无穷大; 若 x 是 NaN,返回值为 NaN。
(logb 10)
⇒ 3
(logb 10.0e20)
⇒ 69
(logb 0)
⇒ -1.0e+INF
本节中的函数用于检测一个对象是否为数值,或是某一特定类型的数值。函数 integerp 和 floatp 可以接受任意类型的 Lisp 对象作为参数(否则它们就没太大用处了),但谓词 zerop 要求参数必须是数值。另见 Predicates on Markers 一节中的 integer-or-marker-p 和 number-or-marker-p。
该谓词检测参数是否为大数(大整数),是则返回 t,否则返回 nil。
与小整数不同,大数即使不满足 eq 相等,也可能满足 = 或 eql 相等。
该谓词检测参数是否为定长数(小整数),是则返回 t,否则返回 nil。小整数可以用 eq 进行比较。
该谓词检测参数是否为浮点数,是则返回 t,否则返回 nil。
该谓词检测参数是否为整数(包含大数与定长数),是则返回 t,否则返回 nil。
该谓词检测参数是否为数值(整数或浮点数均可),是则返回 t,否则返回 nil。
该谓词(名称来自 “natural number自然数”)检测参数是否为非负整数,是则返回 t,否则返回 nil。0 被视为非负整数。
wholenump 是 natnump 的同义词。
该谓词检测参数是否为零,是则返回 t,否则返回 nil。参数必须是数值。
(zerop x) 等价于 (= x 0)。
要判断数值是否相等,通常应使用 =,而不是 eq、eql、equal 这类非数值比较谓词。不同的浮点数对象或大整数对象,在数值上可能相等。如果用 eq 比较,判断的是它们是否为同一个 对象;如果用 eql 或 equal,判断的是它们的值是否 indistinguishable不可区分;而 = 采用纯数值比较,有时会在非数值比较返回 nil 时返回 t,反之亦然。See 浮点数基础。
在 Emacs Lisp 中,如果两个定长数(fixnum)数值相等,它们就是同一个 Lisp 对象。也就是说,对定长数而言,eq 等价于 =。有时用 eq 把未知值与定长数比较会更方便,因为即使未知值不是数字,eq 也不会报错 —— 它接受任意类型的参数。相比之下,如果参数不是数字或标记(marker),= 会抛出错误。不过,只要可以,即使是比较整数,更好的编程习惯仍是使用 =。
有时用 eql 或 equal 比较数字会很有用:只有当两个数类型相同(同为整数或同为浮点数)且值相同时,它们才被视为相等。而 = 可以把一个整数和一个浮点数视为相等。See 相等性谓词。
还有一个细节:由于浮点数运算不精确,直接判断浮点数是否相等通常是不合适的。一般更好的做法是判断近似相等。下面是实现这一功能的函数:
(defvar fuzz-factor 1.0e-6)
(defun approx-equal (x y)
(or (= x y)
(< (/ (abs (- x y))
(max (abs x) (abs y)))
fuzz-factor)))
该函数判断所有参数是否数值上都相等,是则返回 t,否则返回 nil。
该函数行为与 eq 基本一致,仅当两个参数都是数字时例外。它会同时按类型和数值比较数字:
(eql 1.0 1) 返回 nil,但 (eql 1.0 1.0) 和 (eql 1 1) 都返回 t。
它可用于比较小整数和大整数。符号、指数、尾数都相同的浮点数才满足 eql。这与数值比较不同:(eql 0.0 -0.0) 返回 nil,(eql 0.0e+NaN 0.0e+NaN) 返回 t,而 = 的结果正好相反。
该函数判断两个参数是否数值不相等,不相等返回 t,相等返回 nil。
判断每个参数是否严格小于后一个参数,是则返回 t,否则返回 nil。
判断每个参数是否小于等于后一个参数,是则返回 t,否则返回 nil。
判断每个参数是否严格大于后一个参数,是则返回 t,否则返回 nil。
判断每个参数是否大于等于后一个参数,是则返回 t,否则返回 nil。
返回所有参数中的最大值。
(max 20)
⇒ 20
(max 1 2.5)
⇒ 2.5
(max 1 3 2.5)
⇒ 3
返回所有参数中的最小值。
(min -4 1)
⇒ -4
返回 number 的绝对值。
要将整数转换为浮点数,使用函数 float。
返回将 number 转换为浮点数后的结果。如果 number 已经是浮点数,float 原样返回。
有四个函数可将浮点数转换为整数,它们的舍入方式不同。所有这些函数都接受参数 number 和可选参数 divisor。两个参数都可以是整数或浮点数,divisor 也可以是 nil。
如果 divisor 为 nil 或被省略,这些函数将 number 转换为整数;若已是整数则直接返回。
如果 divisor 非-nil,它们会将 number 除以 divisor,再把结果转为整数。
如果 divisor 为 0(整数或浮点数),Emacs 会抛出 arith-error 错误。
通过向零舍入,将 number 转换为整数并返回。
(truncate 1.2)
⇒ 1
(truncate 1.7)
⇒ 1
(truncate -1.2)
⇒ -1
(truncate -1.7)
⇒ -1
通过向下舍入(向负无穷方向),将 number 转换为整数并返回。
如果指定了 divisor,该函数使用与 mod 对应的除法方式,向下舍入。
(floor 1.2)
⇒ 1
(floor 1.7)
⇒ 1
(floor -1.2)
⇒ -2
(floor -1.7)
⇒ -2
(floor 5.99 3)
⇒ 1
通过向上舍入(向正无穷方向),将 number 转换为整数并返回。
(ceiling 1.2)
⇒ 2
(ceiling 1.7)
⇒ 2
(ceiling -1.2)
⇒ -1
(ceiling -1.7)
⇒ -1
通过四舍五入到最近整数,将 number 转换为整数并返回。若数值恰好处于两个整数中间,会舍入到偶数。
(round 1.2)
⇒ 1
(round 1.7)
⇒ 2
(round -1.2)
⇒ -1
(round -1.7)
⇒ -2
Emacs Lisp 提供传统的四种算术运算(addition加、subtraction减、multiplication乘、division除),以及取余、取模、自增 1 和自减 1 函数。除 % 外,这些函数均接受整数和浮点数参数,只要任意一个参数是浮点数,就返回浮点数。
返回 number-or-marker 加 1。 示例:
(setq foo 4)
⇒ 4
(1+ foo)
⇒ 5
该函数不等价于 C 语言的 ++ — 它不会修改变量,只做加法计算。因此继续执行:
foo
⇒ 4
若要真正修改变量,必须配合 setq,如下:
(setq foo (1+ foo))
⇒ 5
返回 number-or-marker 减 1。
对所有参数求和。无参数时返回 0。
(+)
⇒ 0
(+ 1)
⇒ 1
(+ 1 2 3 4)
⇒ 10
- 有两个作用:取负、减法。
单个参数:返回其相反数;
多个参数:从第一个数 number-or-marker 中依次减去后面所有数 more-numbers-or-markers;
无参数:返回 0。
(- 10 1 2 3 4)
⇒ 0
(- 10)
⇒ -10
(-)
⇒ 0
对所有参数求积。无参数时返回 1。
(*)
⇒ 1
(* 1)
⇒ 1
(* 1 2 3 4)
⇒ 24
有一个或多个 divisors除数:将 number 依次除以每个 divisors除数,返回商; 无除数:返回 1/number(即倒数)。每个参数都可以是数值或标记(marker)
若所有参数均为整数,结果为整数,每次除法后向零取整。
(/ 6 2)
⇒ 3
(/ 5 2)
⇒ 2
(/ 5.0 2)
⇒ 2.5
(/ 5 2.0)
⇒ 2.5
(/ 5.0 2.0)
⇒ 2.5
(/ 4.0)
⇒ 0.25
(/ 4)
⇒ 0
(/ 25 3 2)
⇒ 4
(/ -17 6)
⇒ -2
如果将整数除以整数 0,Emacs 会抛出 arith-error 错误(see 错误)。
在使用 IEEE-754 浮点数的系统上,非零浮点数除以 0 会得到正无穷或负无穷(see 浮点数基础);否则,会照常抛出 arith-error 错误。
该函数返回 dividend被除数除以 divisor除数 后的整数余数。参数必须是整数或标记(marker)。
对于任意两个整数 dividend被除数 和 divisor除数,当除数非零时:
(+ (% dividend divisor) (* (/ dividend divisor) divisor))
在 divisor除数 不为零时,结果恒等于 dividend被除数。
(% 9 4)
⇒ 1
(% -9 4)
⇒ -1
(% 9 -4)
⇒ 1
(% -9 -4)
⇒ -1
该函数返回 dividend被除数 对 divisor除数 取模的结果;换句话说,是 dividend被除数 除以 divisor除数 的余数,但符号与除数相同。参数必须是数值或标记。
与 % 不同,mod 允许浮点数参数;它会将商向下取整(向负无穷方向),再用该商计算余数。
若 divisor除数 为 0,如果两个参数都是整数,mod 抛出 arith-error 错误,否则返回 NaN。
(mod 9 4)
⇒ 1
(mod -9 4)
⇒ 3
(mod 9 -4)
⇒ -3
(mod -9 -4)
⇒ -1
(mod 5.5 2.5)
⇒ .5
对于任意两个数值 dividend被除数 和 divisor除数,
(+ (mod dividend divisor) (* (floor dividend divisor) divisor))
恒等于 dividend被除数;若任一参数为浮点数,则可能存在舍入误差;若 dividend被除数 是整数且 divisor除数 为 0,则抛出 arith-error。关于 floor,见 数值转换。
函数 ffloor、fceiling、fround 和 ftruncate 接收一个浮点型参数,并返回一个值为邻近整数的浮点型结果。ffloor 返回不大于参数的最接近整数;fceiling 返回不小于参数的最接近整数;ftruncate 向零方向取最接近的整数;fround 返回最接近的整数。
该函数将 float 向下取整至紧邻的更小整数,并以浮点数形式返回该值。
该函数将 float 向上取整至紧邻的更大整数,并以浮点数形式返回该值。
该函数将 float 向零方向取整为整数,并以浮点数形式返回该值。
该函数将 float 取整至最接近的整数,并以浮点数形式返回该值。若数值恰好处于两个整数的正中间,则返回偶数。
在计算机中,整数以二进制数表示,即由若干 bits位(取值为 0 或 1 的数字)组成的序列。从概念上讲,该位序列在左侧是无限延伸的,最高位全为 0 或全为 1。按位运算会对该序列中的每一位单独操作。例如, shifting移位 操作会将整个序列向左或向右移动一位或多位,并保持原有模式。 Emacs Lisp 中的按位运算仅适用于整数。
ash(arithmetic shift算术移位)将整数 integer 的二进制位向左移动 count 位;若 count 为负数,则向右移动。左移会在右侧补 0;右移会丢弃最右侧的位。从整数运算角度看,ash 等价于将 integer 乘以
2**count,
然后向下取整(向负无穷方向)得到整数结果。
下面是 ash 分别左移、右移一位的示例。示例只展示低位二进制位,高位均与所示最高位保持一致。可以看到,左移一位等价于乘以 2,右移一位等价于除以 2 并向负无穷取整。
(ash 7 1) ⇒ 14
;; Decimal 7 becomes decimal 14.
...000111
⇒
...001110
(ash 7 -1) ⇒ 3
...000111
⇒
...000011
(ash -7 1) ⇒ -14
...111001
⇒
...110010
(ash -7 -1) ⇒ -4
...111001
⇒
...111100
左移或右移两位的示例:
; binary values (ash 5 2) ; 5 = ...000101 ⇒ 20 ; = ...010100 (ash -5 2) ; -5 = ...111011 ⇒ -20 ; = ...101100
(ash 5 -2)
⇒ 1 ; = ...000001
(ash -5 -2)
⇒ -2 ; = ...111110
lsh 是 logical shift逻辑移位的缩写,将整数 integer 向左移动 count 位;若 count 为负数,则向右移动,空出的位一律补 0。若 count 为负,则 integer 必须是定长数(fixnum)或正的大数(bignum),且 lsh 会将负定长数视为无符号数处理:先减去两倍的 most-negative-fixnum 再移位,结果非负。这种特殊行为源于早期 Emacs 仅支持定长数的时代;现在更推荐使用 ash。
除了 integer 与 count 同时为负的情况外,lsh 与 ash 行为一致。下面示例聚焦这些例外情况,并假设使用 30 位定长数。
; binary values (ash -7 -1) ; -7 = ...111111111111111111111111111001 ⇒ -4 ; = ...111111111111111111111111111100 (lsh -7 -1) ⇒ 536870908 ; = ...011111111111111111111111111100
(ash -5 -2) ; -5 = ...111111111111111111111111111011 ⇒ -2 ; = ...111111111111111111111111111110 (lsh -5 -2) ⇒ 268435454 ; = ...001111111111111111111111111110
该函数返回所有参数的按位与结果:当且仅当所有参数的第 n 位都为 1 时,结果的第 n 位为 1。
例如,用 4 位二进制数表示,13 与 12 的按位与结果是 12:1101 与 1100 运算得到 1100。两个数最左侧两位都为 1,因此结果最左侧两位为 1;而最右侧两位至少有一个参数为 0,因此结果最右侧两位为 0。
所以,
(logand 13 12)
⇒ 12
若 logand 无参数,返回 −1。该 logand 数是按位与的单位元,因为其二进制全为 1。若 logand 只传入一个参数,直接返回该参数。
; binary values (logand 14 13) ; 14 = ...001110 ; 13 = ...001101 ⇒ 12 ; 12 = ...001100
(logand 14 13 4) ; 14 = ...001110 ; 13 = ...001101 ; 4 = ...000100 ⇒ 4 ; 4 = ...000100
(logand)
⇒ -1 ; -1 = ...111111
该函数返回所有参数的按位或结果:当且仅当至少一个参数的第 n 位为 1时,结果的第 n 位为 1。无参数时返回 0,是该运算的单位元。logior 只传入一个参数时,直接返回该参数。
; binary values (logior 12 5) ; 12 = ...001100 ; 5 = ...000101 ⇒ 13 ; 13 = ...001101
(logior 12 5 7) ; 12 = ...001100 ; 5 = ...000101 ; 7 = ...000111 ⇒ 15 ; 15 = ...001111
该函数返回所有参数的按位异或结果:当且仅当该位为 1 的参数个数是奇数时,结果的第 n 位为 1。无参数时返回 0,是该运算的单位元。logxor 只传入一个参数时,直接返回该参数。
; binary values (logxor 12 5) ; 12 = ...001100 ; 5 = ...000101 ⇒ 9 ; 9 = ...001001
(logxor 12 5 7) ; 12 = ...001100 ; 5 = ...000101 ; 7 = ...000111 ⇒ 14 ; 14 = ...001110
该函数返回参数的按位取反结果:当且仅当 integer 的第 n 位为 0时,结果的第 n 位为 1,反之亦然。结果等于:−1 − integer。
(lognot 5)
⇒ -6
;; 5 = ...000101
;; becomes
;; -6 = ...111010
该函数返回 integer整数 的 Hamming weight汉明重量:即 integer 二进制表示中 1 的个数。若 integer 为负数,则返回其二进制补码表示中 0 的个数。结果始终非负。
(logcount 43) ; 43 = ...000101011 ⇒ 4 (logcount -43) ; -43 = ...111010101 ⇒ 3
这些数学函数允许整数和浮点数作为参数。
(asin arg) 的返回值是介于
−pi/2
和
pi/2
(包含边界)之间的数值,其正弦值等于 arg。若 arg 超出范围(不在 [−1, 1] 区间内),asin 返回 NaN(非数值)。
(acos arg) 的返回值是介于 0 到
pi
(包含边界)之间的数值,其余弦值等于 arg。若 arg 超出范围(不在 [−1, 1] 区间内),acos 返回 NaN。
(atan y) 的返回值是介于
−pi/2
到
pi/2
(不含边界)之间的数值,其正切值等于 y。若传入可选的第二个参数 x,则 (atan y x) 返回向量 [x, y] 与 X 轴之间的夹角(单位:弧度)。
这是指数函数,返回自然常数 \(e\) 的 arg 次幂(即 \(e^{arg}\))。
该函数返回 arg 以 base 为底的对数值。若未指定 base,则使用自然底数 \(e\)。若 arg 或 base 为负数,log 返回 NaN。
该函数返回 x 的 y 次幂(即 \(x^y\))。
若两个参数均为整数且 y 非负,结果为整数;此场景下若发生溢出会触发错误,需注意。
若 x 是有限负数且 y 是有限非整数,expt 返回 NaN。
该函数返回 arg 的平方根。若 arg 是有限数且小于 0,sqrt 返回 NaN。
此外,Emacs 还定义了以下常用数学常量:
数学常量 \(e\)(值为 2.71828…)。
数学常量 \(pi\)(值为 3.14159…)。
确定性的计算机程序无法生成真正意义上的随机数。对绝大多数用途而言 pseudo-random numbers伪随机数 已经足够。伪随机数序列以确定性方式生成:这些数并非真正随机,但具备模仿随机序列的若干特性。例如,所有可能的取值在伪随机序列中出现的频率大致均等。
伪随机数由 seed value种子值 生成。从任意给定种子出发,random 函数总会生成相同的数值序列。默认情况下,Emacs 会在启动时初始化随机种子,使得每次运行 Emacs 得到的 random 序列(极大概率)互不相同。随机种子通常从系统熵源初始化;但在缺少熵池的旧平台上,种子会取自随机性较弱的易变数据(如当前时间)。
有时你希望随机数序列可复现。例如,调试行为依赖随机序列的程序时,让程序每次运行行为一致会很有帮助。要让序列可复现,执行 (random "")。这会将种子设为当前 Emacs 可执行文件对应的固定值(不同编译版本可能不同)。你也可以使用其他字符串来指定不同的种子。
该函数返回一个伪随机整数。重复调用会生成一系列伪随机整数。
如果 limit 是正整数:返回非负且小于 limit 的整数。否则:返回值可以是任意定长整数(fixnum),即从 most-negative-fixnum 到 most-positive-fixnum 之间的任意整数(see 整数基础)。
如果 limit 是字符串:根据字符串内容设置新种子,后续 random 调用将返回可复现的结果序列。
如果 limit 是 t:按 Emacs 重启的方式重新选取种子,后续 random 调用将返回不可预测的结果序列。
如果你需要用于密码学场景的随机数(nonce),通常不建议使用 random,原因如下:
(random t) 读取系统熵,这也可能影响程序中依赖结果可复现性的其他部分。
random 使用的、与系统相关的伪随机数生成器(PRNG)不一定适合密码学安全场景。
(random t) 不会直接访问系统熵,熵会经过系统相关的 PRNG 处理,可能导致结果存在偏差。
(random t) 会将相关信息散布在 Emacs 内部状态中,扩大内部攻击面。
(random t) 的种子来自密码学强度较弱的数据源。
Emacs Lisp 中的字符串是一个包含有序字符序列的数组。字符串可用作符号、缓冲区和文件的名称;用于向用户发送消息;保存缓冲区之间复制的文本;以及用于许多其他用途。由于字符串非常重要,Emacs Lisp 提供了大量专门用于操作字符串的函数。在 Emacs Lisp 程序中,使用字符串的频率远高于单独的字符。
有关键盘字符事件字符串的特殊注意事项,see 将键盘事件存入字符串。
字符是一种 Lisp 对象,用于表示文本中的单个字符。在 Emacs Lisp 中,字符本质上就是整数;一个整数是否被当作字符,仅取决于它的使用方式。关于 Emacs 中字符的具体表示,see Character Codes。
字符串是固定长度的字符序列。它属于 array数组 类型的序列,意味着其长度在创建后就固定不可修改(see 序列、数组与向量)。与 C 语言不同,Emacs Lisp 字符串 不以 特殊字符码作为结束标志。
因为字符串是数组,同时也是序列,所以你可以使用《序列、数组与向量》中介绍的通用数组与序列函数来操作它们。例如,可以使用 aref 函数访问字符串中的单个字符(see 操作数组的函数)。
在 Emacs 字符串(以及缓冲区)中,非-ASCII 字符有两种文本表示方式:单字节(unibyte) 和多字节(multibyte)。对于大多数 Lisp 编程场景,你无需关心这两种表示方式的区别。详情 see Text Representations。
有时按键序列会用单字节字符串表示。当单字节字符串用作按键序列时,取值在 128~255 范围内的字符串元素代表元字符(meta 字符)(本身是大整数),而非 128~255 范围内的字符编码。字符串无法存储带有 hyper、super 或 alt 修饰键的字符;可以保存 ASCII 控制字符,但不支持其他控制字符,且不区分 ASCII 控制字符的大小写。如果你需要存储这类字符(比如按键序列),必须使用向量而非字符串。有关键盘输入字符的更多信息,see 字符类型。
字符串很适合用来存放正则表达式。你还可以用 string-match 将正则表达式与字符串进行匹配(see Regular Expression Searching)。match-string(see Simple Match Data Access)和 replace-match(see Replacing the Text that Matched)这两个函数,常用于在正则匹配后对字符串进行拆分与修改。
与缓冲区类似,字符串除了保存字符本身,还可以为其中的字符附加文本属性。See Text Properties。所有将文本从字符串复制到缓冲区或其他字符串的 Lisp 原语,都会同时复制对应字符的文本属性。
有关显示字符串或将字符串复制到缓冲区的函数,see Text。有关字符和字符串语法的说明,分别见 《字符类型》和《字符串类型》。有关文本表示方式转换、字符编码和解码的函数,see Non-ASCII Characters。另外注意:不应使用 length 计算字符串在屏幕上的显示宽度,应改用 string-width(see Size of Displayed Text)。
关于通用序列与数组判断函数的更多信息,参见《序列、数组与向量》和《数组》。
如果 object 是字符串,该函数返回 t,否则返回 nil。
如果 object 是字符串或 nil,该函数返回 t,否则返回 nil。
如果 object 是字符串或字符(即整数),该函数返回 t,否则返回 nil。
下面这些函数用于创建字符串:可以从零新建、拼接字符串,或是拆分字符串。(有关基于其他字符串修改内容来创建新字符串的函数,如 string-replace 和 replace-regexp-in-string,请参见 “Search and Replace”。)
本函数返回一个由 character 重复 count 次构成的字符串。如果 count 为负数,会抛出错误。
(make-string 5 ?x)
⇒ "xxxxx"
(make-string 0 ?x)
⇒ ""
通常情况下,如果 character 是 ASCII 字符,结果为单字节字符串。但如果可选参数 multibyte 非 nil,函数会生成多字节字符串。这在后续需要与非-ASCII 字符串拼接,或将部分字符替换为非-ASCII 字符时很有用。
可与此函数对比的其他函数包括 make-vector(see 向量)和 make-list(see 构建 cons 单元与列表)。
返回由给定字符 characters 组成的字符串。
(string ?a ?b ?c)
⇒ "abc"
该函数返回一个新字符串,由原字符串 string 中从索引 start(包含)到 end(不包含)之间的字符组成。第一个字符的索引是 0。只传一个参数时,该函数会直接复制整个 string。
(substring "abcdefg" 0 3)
⇒ "abc"
上例中,‘a’ 的索引是 0,‘b’ 是 1,‘c’ 是 2。索引 3(字符串中第四个字符)标记截取的结束位置。因此从 "abcdefg" 中复制出 ‘abc’。
负数表示从字符串末尾算起,−1 代表最后一个字符的索引。例如:
(substring "abcdefg" -3 -1)
⇒ "ef"
本例中 ‘e’ 的索引是 −3,‘f’ 是 −2,‘g’ 是 −1。因此包含 ‘e’ 和 ‘f’,不包含 ‘g’。
如果 end 为 nil,则代表字符串长度。因此:
(substring "abcdefg" -3 nil)
⇒ "efg"
省略参数 end 等价于传入 nil。由此可知 (substring string 0) 会返回整个 string 的副本。
(substring "abcdefg" 0)
⇒ "abcdefg"
但我们推荐使用 copy-sequence 来完成此操作(see 序列)。
如果从原 string 复制的字符带有文本属性,这些属性也会被复制到新字符串中。See Text Properties。
substring 也接受将向量作为第一个参数。例如:
(substring [a b (c) "d"] 1 3)
⇒ [b (c)]
如果 start 不是整数,或 end 既不是整数也不是 nil,会抛出 wrong-type-argument 错误。如果 start 位置在 end 之后,或任一索引超出字符串范围,会抛出 args-out-of-range 错误。
将此函数与 buffer-substring(see Examining Buffer Contents)对比:后者返回当前缓冲区中一段文本构成的字符串。字符串的起始索引是 0,而缓冲区的起始索引是 1。
功能与 substring 相同,但会丢弃结果中的所有文本属性。此外,start 可以省略或为 nil,等价于 0。因此 (substring-no-properties string) 会返回移除了所有文本属性的 string 副本。
该函数返回一个字符串,由所有参数中的字符(及其文本属性,如果有)组成。参数可以是字符串、数字列表或数字向量;参数本身不会被修改。如果 concat 没有参数,则返回空字符串。
(concat "abc" "-def")
⇒ "abc-def"
(concat "abc" (list 120 121) [122])
⇒ "abcxyz"
;; nil is an empty sequence.
(concat "abc" nil "-def")
⇒ "abc-def"
(concat "The " "quick brown " "fox.")
⇒ "The quick brown fox."
(concat)
⇒ ""
该函数不保证总会分配新字符串。调用者不应依赖结果是新字符串,或与某个已有字符串是 eq 关系。
特别注意:修改返回值可能会意外改变另一个字符串、修改程序中的常量字符串,甚至直接报错。若要得到可以安全修改的字符串,请对结果使用 copy-sequence。
有关其他拼接函数,可参见 “映射函数” 中的 mapconcat、“向量相关函数” 中的 vconcat,以及 “构建 cons 单元与列表” 中的 append。若要将多个命令行参数拼接成可作为 Shell 命令的字符串,见 combine-and-quote-strings。
该函数根据正则表达式 separators(see Regular Expressions)将 string 切分为子串。每一次 separators 的匹配位置都是分割点;分割点之间的子串构成列表返回。
如果 separators 为 nil(或省略),则使用默认值 split-string-default-separators,且函数行为相当于 omit-nulls 为 t。
如果 omit-nulls 为 nil(或省略),当存在连续的 separators 匹配,或分隔符匹配出现在 string 开头 / 结尾时,结果中会包含空字符串。若 omit-nulls 为 t,这些空串会被忽略。
如果可选参数 trim 非-nil,它应为一个正则表达式,用于去掉每个子串开头和结尾的匹配内容。如果修剪后子串为空,则视为空串。
若你需要将字符串拆分为适合 call-process 或 start-process 使用的命令行参数列表,见 split-string-and-unquote。
Examples:
(split-string " two words ")
⇒ ("two" "words")
结果不是 ("" "two" "words" ""),这种情况通常没什么用。如果需要这样的结果,可以显式指定 separators:
(split-string " two words "
split-string-default-separators)
⇒ ("" "two" "words" "")
(split-string "Soup is good food" "o")
⇒ ("S" "up is g" "" "d f" "" "d")
(split-string "Soup is good food" "o" t)
⇒ ("S" "up is g" "d f" "d")
(split-string "Soup is good food" "o+")
⇒ ("S" "up is g" "d f" "d")
空匹配是有效的,除非 split-string 已经通过非空匹配到达字符串末尾,或 string 本身为空,此时不会再寻找末尾的空匹配:
(split-string "aooob" "o*")
⇒ ("" "a" "" "b" "")
(split-string "ooaboo" "o*")
⇒ ("" "" "a" "b" "")
(split-string "" "")
⇒ ("")
不过,当 separators 可以匹配空串时,omit-nulls 通常设为 t,因此上面几个例子中的细节很少实际用到:
(split-string "Soup is good food" "o*" t)
⇒ ("S" "u" "p" " " "i" "s" " " "g" "d" " " "f" "d")
(split-string "Nice doggy!" "" t)
⇒ ("N" "i" "c" "e" " " "d" "o" "g" "g" "y" "!")
(split-string "" "" t)
⇒ nil
某些 “non-greedy非贪婪” 的 separators 可能优先选择空匹配而非非空匹配,会出现有些奇怪但可预期的行为。这类值在实际中同样很少出现:
(split-string "ooo" "o*" t)
⇒ nil
(split-string "ooo" "\\|o+" t)
⇒ ("o" "o" "o")
split-string 中 separators 的默认值。
通常取值为 "[ \f\t\n\r\v]+"。
清理 string 中的空白:将连续空白压缩为单个空格,并去掉 string 首尾所有空白。
删除 string 开头匹配 regexp 的内容。 regexp 默认为 ‘[ \t\n\r]+’。
删除 string 结尾匹配 regexp 的内容。 regexp 默认为 ‘[ \t\n\r]+’。
同时删除 string 开头匹配 trim-left 与结尾匹配 trim-right 的内容。两个正则表达式默认均为 ‘[ \t\n\r]+’。
尝试对 string 自动换行,使每行显示宽度不超过 width。仅在空白处换行。如果存在单个单词长度超过 width,不会截断单词,因此最终 string 显示行可能会比 width 宽。
如果 string 字符数小于 length,直接返回原串。否则返回由前 length 个字符组成的子串。如果提供了可选参数 end,则返回最后 length 个字符组成的字符串。
如果 coding-system 非-nil,会先对 string 编码,再按字节限制长度,结果为不超过 length 字节的单字节字符串。如果 string 包含多字节编码字符(如 utf-8),结果字符串绝不会在字符编码中间被截断。
该函数按字符数或字节数计算长度,因此通常不适合用于显示场景的字符串缩短;此时应使用 truncate-string-to-width、window-text-pixel-size 或 string-glyph-split(see Size of Displayed Text)。
按换行符边界将 string 拆分为字符串列表。如果可选参数 omit-nulls 非-nil,结果中去掉空行。如果 keep-newlines 非-nil,则保留结果字符串末尾的换行符。
使用 padding 作为填充字符,将 string 填充到长度 length。padding 默认为空格。如果 string 本身比 length 长,则不填充。如果 start 为 nil 或省略,填充在 string 尾部;若非-nil,则填充在头部。
移除 string 末尾可能存在的最后一个换行符。
你可以通过本节描述的操作来修改可变字符串的内容。See 可变性。
修改已有字符串内容最基本的方式是使用 aset(see 操作数组的函数)。(aset string idx char) 将字符 char 存入字符串 string 的字符索引 idx 处。如果需要,它会自动将纯 ASCII string 转换为多字节字符串(see Text Representations);但如果 char 是非-ASCII 字符(而非原始字节),我们建议你始终确保 string 是多字节类型(例如使用 string-to-multibyte, see Converting Text Representations)。
若要清空存放密码的字符串,可使用 clear-string:
该函数将 string 变为单字节字符串,并将其内容清空为空字符。它还可能改变 string 的长度。
如果参数表示同一个字符,返回 t,否则返回 nil。如果 case-fold-search 非-nil,此函数会忽略大小写差异。
(char-equal ?x ?x)
⇒ t
(let ((case-fold-search nil))
(char-equal ?x ?X))
⇒ nil
如果两个字符串的字符完全匹配,返回 t。参数也可以是符号,此时会使用符号名进行比较。比较始终区分大小写,与 case-fold-search 无关。
比较两个字符串时,该函数等价于 equal(see 相等性谓词)。特别地,它会忽略字符串的文本属性;如果需要区分仅属性不同的字符串,使用 equal-including-properties。但与 equal 不同,只要任一参数不是字符串或符号,string-equal 就会报错。
(string-equal "abc" "abc")
⇒ t
(string-equal "abc" "ABC")
⇒ nil
(string-equal "ab" "ABC")
⇒ nil
当且仅当单字节字符串与多字节字符串包含的所有字符编码都在 0–127(ASCII)范围内时,string-equal 会认为它们相等。See Text Representations。
string= 是 string-equal 的别名。
string-equal-ignore-case 比较字符串时忽略大小写,类似于 case-fold-search 为 t 时的 char-equal。
该函数会根据指定 locale区域 的排序规则比较两个字符串,若二者相等则返回 t;若未指定区域,默认使用当前系统的区域设置。排序规则的判定不仅基于字符串 string1 和 string2 中字符的字典序,还包含字符间关联关系的额外规则。这类规则通常由 Emacs 运行时的区域环境,以及编译 Emacs 时链接的标准 C 库共同定义4。
例如,部分编码点不同但语义相同的字符(如不同的重音符 Unicode 字符),在某些区域设置下会被判定为相等:
(string-collate-equalp (string ?\uFF40) (string ?\u1FEF))
⇒ t
可选参数 locale(字符串类型)会覆盖当前用于排序的区域设置标识符。该参数的值依赖于操作系统:POSIX 系统可使用 locale 设置值 "en_US.UTF-8",而在 MS-Windows 系统上则需使用例如 "enu_USA.1252" 这样的值。
若 ignore-case 参数非-nil,字符会先转换为小写形式,再进行大小写不敏感的比较。但如果底层系统库未提供特定区域的排序规则,此函数会降级使用 string-equal 进行比较 —— 这种情况下 ignore-case 参数会被忽略,比较始终是大小写敏感的。
要在 MS-Windows 系统上模拟符合 Unicode 标准的排序规则,需将 w32-collate-ignore-punctuation 绑定为非-nil,因为 MS-Windows 系统的区域设置中,字符集部分无法设置为 "UTF-8"。
如果系统不支持区域设置环境,此函数的行为将等同于 string-equal。
请勿使用此函数比较文件名是否相等,因为文件系统通常不遵循排序功能所实现的字符串语言等效规则。
该函数逐个字符比较两个字符串。它会同时扫描两个字符串,找到第一对不匹配的对应字符:
若这两个字符中较小的字符来自 string1,则判定 string1 更小,函数返回 t;
若较小的字符来自 string2,则判定 string1 更大,函数返回 nil;
若两个字符串完全匹配,返回值为 nil。
字符对的比较基于其字符编码值: 需注意,在 ASCII 字符集中,小写字母的数值大于对应的大写字母; 数字和多数标点符号的数值小于大写字母; 任意 ASCII 字符小于非-ASCII 字符; 单字节非-ASCII 字符始终小于多字节非-ASCII 字符(see Text Representations)。
(string-lessp "abc" "abd")
⇒ t
(string-lessp "abd" "abc")
⇒ nil
(string-lessp "123" "abc")
⇒ t
当两个字符串长度不同时:
若匹配到 string1 的长度仍未发现差异,则返回 t;
若匹配到 string2 的长度仍未发现差异,则返回 nil;
空字符串小于任何非空字符串。
(string-lessp "" "abc")
⇒ t
(string-lessp "ab" "abc")
⇒ t
(string-lessp "abc" "")
⇒ nil
(string-lessp "abc" "ab")
⇒ nil
(string-lessp "" "")
⇒ nil
参数也可传入符号(symbol),此时会比较其打印名称(print name)。
string< 是 string-lessp 的别名。
该函数按相反顺序比较 string1 和 string2,等效于调用 (string-lessp string2 string1)。
string> 是 string-greaterp 的别名。
若在指定 locale 设置的排序规则中 string1 小于 string2,该函数返回 t(locale区域 设置默认使用当前系统值)。排序规则不仅取决于字符串中字符的词典顺序,还遵循字符间关系的额外规则 —— 通常由 Emacs 运行时的区域设置环境,以及编译 Emacs 所链接的标准 C 库决定。
例如,排序时可能忽略标点和空白字符(see 序列):
(sort '("11" "12" "1 1" "1 2" "1.1" "1.2")
:lessp #'string-collate-lessp)
⇒ ("11" "1 1" "1.1" "12" "1 2" "1.2")
此行为依赖于操作系统:例如在 Cygwin 系统中,无论区域设置如何,标点和空白字符永远不会被忽略。
可选参数 locale(字符串类型)会覆盖当前用于排序的区域设置标识符。该值依赖于操作系统:POSIX 系统可使用 "en_US.UTF-8",而 MS-Windows 系统需使用例如 "enu_USA.1252"。若将 locale 设置为 "POSIX" 或 "C",string-collate-lessp 的行为将等同于 string-lessp:
(sort '("11" "12" "1 1" "1 2" "1.1" "1.2")
:lessp (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX")))
⇒ ("1 1" "1 2" "1.1" "1.2" "11" "12")
若 ignore-case 非-nil,字符会转换为小写后进行大小写不敏感比较。但如果底层系统库未提供特定区域的排序规则,函数会降级使用 string-lessp,此时 ignore-case 参数被忽略,比较始终大小写敏感。
要在 MS-Windows 系统上模拟符合 Unicode 标准的排序,需将 w32-collate-ignore-punctuation 绑定为非-nil(因 MS-Windows 不支持将区域设置的字符集设为 "UTF-8")。
若系统不支持区域设置环境,此函数行为等同于 string-lessp。
该函数按词典顺序比较字符串,但会将连续的数字字符视为十进制数进行比较。因此根据该判定规则,‘foo2.png’ 会被判定为 “samller小于” ‘foo12.png’ —— 即便从纯词典顺序看,‘12’ “smaller小于” ‘2’。
若 string1 是 string2 的前缀(即 string2 以 string1 开头),函数返回非-nil。若可选参数 ignore-case 非-nil,比较时会忽略大小写差异。
若 suffix 是 string 的后缀(即 string 以 suffix 结尾),函数返回非-nil。若可选参数 ignore-case 非-nil,比较时会忽略大小写差异。
返回子串 needle 在字符串 haystack 中首次出现的位置。若指定 start-pos 非-nil,则从 haystack 的该位置开始搜索;未找到匹配时返回 nil。该函数仅比较字符串的字符本身,忽略文本属性,且匹配始终是大小写敏感的。
该函数比较 string1 和 string2 的指定子串:
string1 的比较范围为从 start1(包含)到 end1(不包含);start1 为 nil 表示字符串起始位置,end1 为 nil 表示字符串长度;
string2 的比较范围同理(start2 到 end2)。
字符串比较基于字符的数值。如果两个字符串第一个不同的字符中,str1 对应的字符数值更小,那么 str1 就被认为小于 str2。若 ignore-case 非-nil,字符会先通过当前缓冲区的大小写表(see 大小写转换表)转换为大写,再进行比较。单字节字符串会转换为多字节形式参与比较(see Text Representations),因此单字节字符串与其多字节转换版本始终被判定为相等。
若两个字符串的指定部分完全匹配,函数返回值为 t。否则返回一个整数,该整数会指明两个字符串开头连续匹配的字符数量,以及哪个字符串更小:
整数的绝对值等于两个字符串开头匹配的字符数加 1;若 string1(或其指定部分)更小,该整数为负数。
该函数返回源字符串 string1 与目标字符串 string2 之间的 Levenshtein distance莱文斯坦距离。Levenshtein distanc 指将源字符串转换为目标字符串所需的单字符修改操作(删除、插入或替换)次数;它是字符串间 edit distance 的一种定义方式。
字符串的大小写会影响计算出的距离值,但字符串的文本属性会被忽略。若可选参数 bytecompare 非-nil,该函数会基于字节(而非字符)计算距离。基于字节的比较使用 Emacs 内部的字符表示方式,因此对于包含原始字节的多字节字符串,此方式会产生不准确的结果(see Text Representations);若需要对原始字节获得准确结果,可通过编码将字符串转换为单字节形式(see Explicit Encoding and Decoding)。
该函数的作用与 assoc 类似,但要求 key 必须是字符串或符号,且比较过程通过 compare-strings 完成。符号会在比对前被转换为字符串。若可选参数 case-fold 非-nil,key 与 alist 中的元素会先转换为大写形式再进行比较。与 assoc 不同的是,该函数还能匹配 alist 中为字符串或符号的元素(而非仅 cons 类型元素)。具体而言,alist 可以是一个由字符串或符号组成的列表,而非严格意义上的关联列表(alist)。See 关联列表。
另可参考 Comparing Text 中的 compare-buffer-substrings 函数,该函数用于比较缓冲区中的文本。而 string-match 函数可将正则表达式与字符串进行匹配,也可用于某种形式的字符串比较;参见 Regular Expression Searching。
See also the function compare-buffer-substrings in
本节介绍用于在字符、字符串和整数之间进行转换的函数。format(see 格式化字符串)和 prin1-to-string(see 输出函数)也可将 Lisp 对象转换为字符串。read-from-string(see 输入函数)能够将 Lisp 对象的字符串表示形式转换为对象。string-to-multibyte 和 string-to-unibyte 函数用于转换字符串的文本编码形式(see Converting Text Representations)。
有关生成文本字符和通用输入事件的文本描述的函数,see 文档(single-key-description 和 text-char-description)。这些函数主要用于生成帮助信息。
该函数返回一个字符串,内容为数字 number 的十进制打印形式。若参数为负数,返回值以负号开头。
(number-to-string 256)
⇒ "256"
(number-to-string -23)
⇒ "-23"
(number-to-string -23.5)
⇒ "-23.5"
int-to-string 是该函数的半废弃别名。
另请参见《格式化字符串》章节中的 format 函数。
该函数返回字符串 string 中字符对应的数值。若 base 非-nil,则其必须是 2 到 16(包含边界)之间的整数,此时将按该进制转换整数。若 base 为nil,则使用十进制。浮点数值转换仅支持十进制;我们未实现其他进制的浮点数转换,因为这需要大量额外工作,且实用性不高。
解析过程会跳过 string 开头的空格和制表符,然后读取 string 中能被解释为指定进制数字的最长部分。(在部分系统中,会忽略开头的其他空白字符,而非仅空格和制表符。)若 string 无法被解释为数字,该函数返回 0。
(string-to-number "256")
⇒ 256
(string-to-number "25 is a perfect square.")
⇒ 25
(string-to-number "X256")
⇒ 0
(string-to-number "-4.5")
⇒ -4.5
(string-to-number "1e5")
⇒ 100000.0
该函数返回一个新字符串,其中包含单个字符 character。由于 string 函数的功能更通用,此函数已半废弃。See 创建字符串。
该函数返回字符串 string 的第一个字符。其功能基本等同于(aref string 0),区别在于若字符串为空,该函数返回 0(当 string 首个字符为空字符(ASCII 码 0)时,返回值同样为 0)。若该函数的实用性不足以保留,未来可能会被移除。
以下是其他可用于字符串转换的函数:
concat将向量或列表转换为字符串。 See 创建字符串。
vconcat将字符串转换为向量。 See 向量相关函数。
append将字符串转换为列表。 See 构建 cons 单元与列表。
byte-to-string将一个字节的字符数据转换为单字节字符串。 See Converting Text Representations。
Formatting格式化 指的是在一个常量字符串的不同位置代入计算所得的值,从而构造出一个新字符串。这个常量字符串控制着其他值的打印方式和显示位置,它被称为 format string格式字符串。
格式化常用于生成需要显示的消息。实际上,message 和 error 函数也提供了本节所描述的格式化功能;它们与 format-message 的区别仅在于对格式化结果的使用方式不同。
该函数返回一个与 string 等效的字符串,其中所有 format specifications格式说明符 都会被替换为对应 objects 的编码形式。参数 objects 是待格式化的计算结果值。
string 中除格式说明符外的其他字符,会直接复制到输出结果中(包括其文本属性,如果有的话)。格式说明符本身的所有文本属性,都会复制到参数 objects 生成的字符串表示上。
输出字符串不一定是新分配的。例如,若 x 是字符串 "foo",表达式 (eq x (format x)) 和 (eq x (format "%s" x)) 都可能返回 t。
该函数的行为与 format 类似,区别在于它还会根据 text-quoting-style 的值,转换字符串 string 中的重音符 (`) 和撇号 (')。
通常,格式字符串中的重音符和撇号会转换为配对的弯引号,例如 "Missing `%s'" 可能会生成 "Missing ‘foo’"。有关如何影响或禁止此转换的说明,see 文本引用样式。
格式说明符是以 ‘%’ 开头的字符序列。因此,如果字符串 string 中包含 ‘%d’,format 函数会将其替换为待格式化值(参数 objects 中的一个)的打印形式。例如:
(format "The value of fill-column is %d." fill-column)
⇒ "The value of fill-column is 72."
由于 format 会将 ‘%’ 字符解析为格式说明符,因此 切勿 将任意字符串作为第一个参数传入。当该字符串由某些 Lisp 代码生成时,这一点尤为重要。除非确定字符串中绝不会包含任何 ‘%’ 字符,否则应将下文所述的 ‘"%s"’ 作为第一个参数,待传入的字符串作为第二个参数,示例如下:
(format "%s" arbitrary-string)
某些格式说明符要求值为特定类型。如果传入的值不符合要求,会触发错误。
以下是有效的格式说明符对照表:
将说明符替换为对象的无引号打印表示形式(即使用 princ 而非 prin1 — see 输出函数)。因此,字符串仅以其内容表示,不带 ‘"’ 字符;符号也不会显示 ‘\’ 字符。
若对象是字符串,其文本属性会复制到输出结果中。‘%s’ 本身的文本属性也会被复制,但对象的文本属性优先级更高。
将说明符替换为对象的带引号打印表示形式(即使用 prin1 — see 输出函数)。因此,字符串会被 ‘"’ 字符包裹,特殊字符前会按需显示 ‘\’ 字符。
将说明符替换为整数的八进制表示形式。负整数的格式化方式依赖于具体平台。该对象也可以是浮点数,此时会被格式化为整数(舍弃小数部分)。
将说明符替换为有符号整数的十进制表示形式。该对象也可以是浮点数,此时会被格式化为整数(舍弃小数部分)。
将说明符替换为整数的十六进制表示形式。负整数的格式化方式依赖于具体平台。‘%x’ 使用小写字母,‘%X’ 使用大写字母。该对象也可以是浮点数,此时会被格式化为整数(舍弃小数部分)。
将说明符替换为对应值的字符。
将说明符替换为浮点数的指数表示形式。
将说明符替换为浮点数的小数点表示形式。
将说明符替换为浮点数的表示形式(指数表示或小数点表示二选一)。若指数小于 −4 或大于等于精度值(默认值:6),则使用指数表示。默认情况下,结果的小数部分会去除末尾的零,且仅当小数点后有数字时才显示小数点。
将说明符替换为单个 ‘%’。该格式说明符较为特殊:仅支持 ‘%%’ 这一种形式,且不使用任何值。例如,(format "%% %d" 30) 会返回 "% 30"。
任何其他格式字符都会触发 ‘Invalid format operation无效的格式操作’ 错误。
以下是若干示例(假设使用默认的 text-quoting-style 设置):
(format "The octal value of %d is %o,
and the hex value is %x." 18 18 18)
⇒ "The octal value of 18 is 22,
and the hex value is 12."
(format-message
"The name of this buffer is ‘%s’." (buffer-name))
⇒ "The name of this buffer is ‘strings.texi’."
(format-message
"The buffer object prints as `%s'." (current-buffer))
⇒ "The buffer object prints as ‘strings.texi’."
默认情况下,格式说明符按顺序对应 objects 中的各个值。因此,字符串 string 中的第一个格式说明符使用第一个值,第二个格式说明符使用第二个值,依此类推。多余的格式说明符(无对应值的说明符)会触发错误,而多余的待格式化值则会被忽略。
格式说明符可包含 field number字段编号:即在起始的 ‘%’ 后紧跟一个十进制数字,再加上一个字面美元符号 ‘$’。此字段编号会让格式说明符使用指定编号的参数,而非下一个参数。字段编号从 1 开始。一个格式字符串中只能包含编号格式说明符或无编号格式说明符二者之一,例外情况是 ‘%%’ 可与编号格式说明符混用。
(format "%2$s, %3$s, %%, %1$s" "x" "y" "z")
⇒ "y, z, %, x"
在 ‘%’ 和 field number字段编号(如有)之后,可添加特定的 flag characters标志字符。
标志 ‘+’ 会在非负数前添加一个加号,使其始终带有符号。 将空格作为标志时,会在非负数前插入一个空格。(否则,非负数会直接以第一位数字开头。) 这些标志用于保证非负数与负数占用相同的列宽。它们仅对 ‘%d’、‘%e’、‘%f’、‘%g’ 生效,在其他格式中会被忽略;如果同时使用这两个标志,‘+’ 优先。
标志 ‘#’ 指定一种备用输出形式,具体行为取决于所用格式:
标志 ‘0’ 会确保填充字符为 ‘0’,而不是空格。该标志对 ‘%s’、‘%S’、‘%c’ 等非数值说明符无效(这些说明符虽接受 ‘0’ 标志,但仍用 空格 填充)。
标志 ‘-’,若指定了宽度,填充字符会添加在右侧而非左侧。若 ‘-’ 和 ‘0’ 同时出现,‘0’ 标志会被忽略。
(format "%06d is padded on the left with zeros" 123)
⇒ "000123 is padded on the left with zeros"
(format "'%-6d' is padded on the right" 123)
⇒ "'123 ' is padded on the right"
(format "The word '%-7s' actually has %d letters in it."
"foo" (length "foo"))
⇒ "The word 'foo ' actually has 3 letters in it."
格式说明符可指定 width宽度,宽度是一个十进制数字,位于 field number字段编号 和 flag characters标志字符 之后。如果对象的打印表示形式长度小于该宽度, format 会填充字符将其补齐。宽度引入的填充字符默认是左侧的空格:
(format "%5d is padded on the left with spaces" 123)
⇒ " 123 is padded on the left with spaces"
若宽度过小,format 不会截断对象的打印表示形式。因此,可通过宽度指定列之间的最小间距,且无需担心信息丢失。以下两个示例中,‘%7s’ 指定最小宽度为 7:第一个示例中,替换 ‘%7s’ 的字符串仅 3 个字符,需填充 4 个空格;第二个示例中,字符串 "specification" 长度为 13,但不会被截断。
(format "The word '%7s' has %d letters in it."
"foo" (length "foo"))
⇒ "The word ' foo' has 3 letters in it."
(format "The word '%7s' has %d letters in it."
"specification" (length "specification"))
⇒ "The word 'specification' has 13 letters in it."
所有格式说明符均可在 field number字段编号、flag标志和 width宽度(如果存在)之后,都允许使用一个可选的 precision精度。精度由一个小数点 ‘.’ 后跟数字串组成。
对于浮点型格式说明符(‘%e’ 和 ‘%f’ ),精度指定小数点后显示的位数;若精度为 0,小数点也会省略。
对于 ‘%g’,精度指定显示多少位有效数字(有效数字包括小数点前第一位和小数点后所有数字);若精度为 0 或未指定,则按 1 处理。
对于 ‘%s’ 和 ‘%S’,精度将字符串截断至指定长度,因此 ‘%.3s’ 仅显示 object对象 表示形式的前 3 个字符。
对于其他说明符:精度的效果与本地 printf 系列库函数的行为一致。
如果你打算稍后在格式化后的字符串上使用 read 函数来取回格式化值的副本,请使用能让 read 重建该值的格式说明符。
要以这种可还原的方式格式化数字,你可以w使用 ‘%s’ 和 ‘%S’;仅格式化整数时,你还可使用 ‘%d’;仅格式化非负整数时,你还可以使用 ‘#x%x’ 和 ‘#o%o’。
其他格式可能存在问题;例如,‘%d’ 和 ‘%g’ 可能会错误处理 NaN 并丢失精度与类型信息,而 ‘#x%x’ 和 ‘#o%o’ 可能会错误处理负整数)。See 输入函数。
本节描述的函数仅支持固定的一组格式说明符。下一节将介绍函数 format-spec,该函数可支持自定义格式说明符,例如 ‘%a’ 或 ‘%z’。
有时,让用户和 Lisp 程序都能通过自定义格式控制字符串来控制特定文本的生成方式会很实用。例如,一个格式字符串可以定义如何显示某人的名、姓和电子邮箱地址。使用上一节介绍的 format 函数,该格式字符串可能形如 "%s %s <%s>"。但这种方式很快会变得不实用 — 因为无法直观区分每个格式说明符对应哪一项信息。
针对这类场景,更方便的格式字符串可以写成类似 "%f %l <%e>" 这样的形式,其中每个格式字符都带有更明确的语义信息,并且可以很方便地与其他格式字符重新排列,让用户更容易自定义这类格式字符串。
本节介绍的 format-spec 函数实现了与 format 类似的功能,区别在于它可以处理使用任意格式字符的格式控制字符串。
该函数根据 spec-alist 中指定的转换规则,从格式字符串 template 生成并返回一个字符串。spec-alist 是一个关联列表(alist,see 关联列表),其形式为 (letter . replacement)。格式化最终字符串时,template 中每个形如 %letter 的格式说明符都会被对应的 replacement 替换。
template 中除格式说明符外的其他字符(包括其可能附带的文本属性)会直接复制到输出结果中;格式说明符自身的任何文本属性也会复制到其对应的替换内容上。
使用 alist关联列表 指定转换规则具备以下实用特性:
替换内容(REPLACEMENT) 也可以是一个无参函数,该函数返回用于替换的字符串。仅当 TEMPLATE 中使用了对应的 字母(LETTER) 时,这个函数才会被调用。例如,这一特性可用于避免在不需要时触发输入提示。
可选参数 ignore-missing 用于指定如何处理 template 中存在但 spec-alist 中未找到的格式说明符字符:
若为 nil 或省略该参数,函数会抛出错误;
若为 ignore,这些格式说明符会原样保留在输出中(包括其可能的文本属性);
若为 delete,这些格式说明符会从输出中移除;
其他非-nil 值的处理方式与 ignore 相同,但所有 ‘%%’ 也会原样保留在输出中。
若可选参数 split 为非-nil,format-spec 不会返回单个字符串,而是根据替换操作的执行位置,将结果拆分为字符串列表。例如:
(format-spec "foo %b bar" '((?b . "zot")) nil t)
⇒ ("foo " "zot" " bar")
format-spec 接受的格式说明符语法与 format 类似,但并非完全相同。两种函数中,格式说明符均是以 ‘%’ 开头、以字母(如 ‘s’)结尾的字符序列。
与 format 不同(format 会为固定的格式说明符字符集赋予特定含义),format-spec 接受任意格式说明符字符,且对所有字符一视同仁。例如:
(setq my-site-info
(list (cons ?s system-name)
(cons ?t (symbol-name system-type))
(cons ?c system-configuration)
(cons ?v emacs-version)
(cons ?e invocation-name)
(cons ?p (number-to-string (emacs-pid)))
(cons ?a user-mail-address)
(cons ?n user-full-name)))
(format-spec "%e %v (%c)" my-site-info)
⇒ "emacs 27.1 (x86_64-pc-linux-gnu)"
(format-spec "%n <%a>" my-site-info)
⇒ "Emacs Developers <[email protected]>"
格式说明符中,‘%’ 后可紧跟任意数量的以下标志字符,用于修改替换行为的相关特性。
该标志会使宽度指定的填充字符从空格变为 ‘0’;
该标志会使宽度指定的填充字符插入在右侧而非左侧;
若指定了宽度和精度,该标志会将替换内容从左侧截断至指定的宽度和精度;
若指定了宽度和精度,该标志会将替换内容从右侧截断至指定的宽度和精度;
该标志会将替换后的文本转换为大写(see Lisp 中的大小写转换);
该标志会将替换后的文本转换为小写(see Lisp 中的大小写转换)。
使用相互矛盾的标志(例如同时指定大小写转换)的结果是未定义的。
与 format 一致,格式说明符中可包含:
宽度:紧跟在所有标志后的十进制数字;
精度:紧跟在所有标志和宽度后的、以小数点 ‘.’ 开头的十进制数字。
若替换内容的字符数少于指定宽度,会在左侧填充字符:
(format-spec "%8a is padded on the left with spaces"
'((?a . "alpha")))
⇒ " alpha is padded on the left with spaces"
若替换内容的字符数多于指定精度,会从右侧截断:
(format-spec "%.2a is truncated on the right"
'((?a . "alpha")))
⇒ "al is truncated on the right"
以下是一个结合了上述多个特性的复杂示例:
(setq my-battery-info
(list (cons ?p "73") ; Percentage
(cons ?L "Battery") ; Status
(cons ?t "2:23") ; Remaining time
(cons ?c "24330") ; Capacity
(cons ?r "10.6"))) ; Rate of discharge
(format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info)
⇒ "BAT : 73% (02:23 left)"
(format-spec "%>^-3L : %3p%% (%05t left)"
(cons (cons ?L "AC")
my-battery-info))
⇒ "AC : 73% (02:23 left)"
如本节示例所示,format-spec 常用于选择性格式化各类不同信息。这一特性在支持用户自定义格式字符串的程序中尤为实用 —— 用户可通过常规语法,按任意期望的顺序,仅格式化程序提供的部分信息。
大小写转换函数用于更改单个字符或字符串内容的大小写形式。这些函数通常仅转换字母字符(即从 ‘A’ 到 ‘Z’、从 ‘a’ 到 ‘z’ 的字母,以及非-ASCII 字母);其他字符保持不变。你可以通过指定一个大小写转换表来自定义大小写转换的映射规则(see 大小写转换表)。
这些函数不会修改作为参数传入的字符串本身。
以下示例使用字符 ‘X’ 和 ‘x’,它们的 ASCII 码分别为 88 和 120。
该函数将 string-or-char(可以是单个字符或字符串)转换为小写形式。
当 string-or-char 是字符串时,函数返回一个新字符串,其中参数里所有大写字母均被转换为小写;当 string-or-char 是单个字符时,函数返回对应的小写字符(以整数形式表示);若原字符已是小写,或并非字母,则返回值与原字符相同。
(downcase "The cat in the hat")
⇒ "the cat in the hat"
(downcase ?X)
⇒ 120
该函数将 string-or-char(可以是单个字符或字符串)转换为大写形式。
当 string-or-char 是字符串时,函数返回一个新字符串,其中参数里所有小写字母均被转换为大写;当 string-or-char 是单个字符时,函数返回对应的大写字符(以整数形式表示);若原字符已是大写,或并非字母,则返回值与原字符相同。
(upcase "The cat in the hat")
⇒ "THE CAT IN THE HAT"
(upcase ?x)
⇒ 88
该函数对字符串或字符进行首字母大写格式化。如果 string-or-char 是字符串,函数会返回一个新字符串,其内容是 string-or-char原字符串 的副本,且其中每个单词都被首字母大写。这意味着:每个单词的第一个字符转为大写,其余字符均转为小写。
单词的定义是:在当前语法表中被归类为单词组成符语法类的连续字符序列(see Table of Syntax Classes);如果 case-symbols-as-words 非-nil,那么被归类为符号组成符语法类的字符也会被视为单词组成符。
当 string-or-char 是单个字符时,该函数的作用与 upcase 完全相同。
(capitalize "The cat in the hat")
⇒ "The Cat In The Hat"
(capitalize "THE 77TH-HATTED CAT")
⇒ "The 77th-Hatted Cat"
(capitalize ?x)
⇒ 88
如果 string-or-char 是字符串,此函数会将 string-or-char 中每个单词的首字母大写,不修改首字母以外的任何字母。它返回一个新字符串,内容是 string-or-char 的副本,其中每个单词的首字母被转换为大写。
此函数对 “单词” 的定义与上文 capitalize 中描述的一致,并且 case-symbols-as-words 对单词组成字符的作用也相同。
当 upcase-initials 的参数是一个字符时,其效果与 upcase 相同。
(upcase-initials "The CAT in the hAt")
⇒ "The CAT In The HAt"
注意:大小写转换并非码点的一一映射,结果的长度可能与参数长度不同。此外,由于传入字符会强制返回类型为字符,函数无法执行正确的替换,因此结果可能与处理单字符字符串时不同。例如:
(upcase "fi") ; note: single character, ligature "fi"
⇒ "FI"
(upcase ?fi)
⇒ 64257 ; i.e. ?fi
为避免这种情况,在将字符传入任一大小写转换函数之前,必须先使用 string 函数将其转换为字符串。当然,不能对结果的长度做任何假设。
其他字符也可能具有特殊的大小写转换规则。这些字符都拥有由 Unicode 标准定义的非-nil 字符属性 special-uppercase、special-lowercase 或 special-titlecase(see Character Properties)。这些属性定义的特殊大小写转换规则会覆盖当前的大小写转换表(see 大小写转换表)。
有关字符串比较的函数,see 字符与字符串的比较;其中部分函数会忽略大小写差异,或可选择忽略大小写差异。
你可以通过安装专门的 case table大小写转换表 来自定义大小写转换行为。大小写转换表规定了大写字母与小写字母之间的映射关系,它既影响作用于 Lisp 对象的大小写转换函数(见上一节),也影响作用于缓冲区文本的相关函数(see Case Changes)。每个缓冲区都拥有一个大小写转换表,同时还存在一个标准大小写转换表,用于初始化新建缓冲区的大小写转换表。
大小写转换表是一个字符表(char-table,see 字符表),其子类型为 case-table。该字符表将每个字符映射到对应的小写字符。它额外包含三个槽位,用于存放相关映射表:
大写表:将每个字符映射为对应的大写字符。
规范化表:将一组大小写相关的字符全部映射为该组中的某个特定成员。
等价表:将一组大小写相关的字符中的每个字符,映射为该组中的下一个字符。
在简单场景下,你只需要指定到小写的映射即可,另外三张相关表会由该表自动计算生成。
对于某些语言,大写与小写字母并非一一对应。可能存在两个不同的小写字母对应同一个大写字母。这类情况下,你必须同时指定小写与大写的映射。
部分字符拥有预定义的特殊大小写转换规则,默认情况下会覆盖当前的大小写转换表。这些字符拥有由 Unicode 标准定义的非-nil 字符属性:special-uppercase、special-lowercase 或 special-titlecase(see Character Properties)。典型例子是 U+00DF 拉丁小写字母尖 S ß,默认情况下会被转为大写字符串 "SS",而非 U+1E9E 拉丁大写字母尖 S。若要强制这些字符遵循大小写转换表的转换规则,可将对应 Unicode 属性设为 nil:
(upcase "ß") => "SS" (put-char-code-property ?ß 'special-uppercase nil) (upcase "ß") => "ẞ"
大小写转换表中的 canonicalize 额外槽位,将每个字符映射到一个规范等价字符;任何两个通过大小写转换关联的字符,都拥有相同的规范等价字符。例如,‘a’ 与 ‘A’ 因大小写转换相关,它们应当拥有相同的规范等价字符(可以统一为 ‘a’,也可以统一为 ‘A’)。
equivalences 额外槽位是一张映射表,它对每个等价类(拥有相同规范等价字符的字符集合)进行循环置换。(对于普通 ASCII,它会将 ‘a’ 映射到 ‘A’,‘A’ 映射到 ‘a’,其他等价字符组同理。)
构建大小写转换表时,你可以为 canonicalize 传入 nil,Emacs 会根据小写与大写映射自动填充该槽位。你也可以为 equivalences 传入 nil,Emacs 会根据 canonicalize 自动填充该槽位。在实际使用中的大小写转换表里,这两个组成部分都不为 nil。不要在未指定 canonicalize 的情况下尝试手动指定 equivalences。
以下是用于操作大小写转换表的函数:
若 object 是合法的大小写转换表,该谓词函数返回非-nil。
将 table 设置为标准大小写转换表,后续新建的缓冲区都会使用它。
返回当前的标准大小写转换表。
返回当前缓冲区的大小写转换表。
将当前缓冲区的大小写转换表设为 table。
with-case-table 宏会保存当前大小写转换表,将 table 设为当前表,执行 body 中的表达式,最后恢复原大小写转换表。返回值为 body 中最后一个表达式的值。即使通过 throw 或错误发生异常退出(see 非局部退出),也会恢复原大小写转换表。
部分语言环境会修改 ASCII 字符的大小写转换规则;例如在土耳其语环境中,ASCII 大写字母 I 会被转为土耳其语无点 i (‘ı’)。这会干扰需要标准 ASCII 大小写转换的代码,比如基于 ASCII 的网络协议实现。这种情况下,可以使用 with-case-table 宏并搭配变量 ascii-case-table,它保存了未被修改的 ASCII 字符集大小写转换表。
ASCII 字符集专用的大小写转换表。任何语言环境设置都不应修改它。
下面三个函数是用于定义非-ASCII 字符集包的便利子例程。它们会修改指定的大小写转换表 case-table,同时也会修改标准语法表。See Syntax Tables。通常你会用这些函数来修改标准大小写转换表。
该函数指定一对对应的字母,一个大写字母和一个小写字母。
将字符 l 和 r 设为一对匹配的、大小写无关的分隔符。
将字符 char 设为大小写不变字符,并指定其语法为 syntax。
显示当前缓冲区的大小写转换表内容的描述信息。
list列表 表示由零个或多个元素组成的序列(元素可以是任意 Lisp 对象)。列表与向量的重要区别在于:两个或多个列表可以共享部分结构;此外,你可以在列表中插入或删除元素,而无需复制整个列表。
Lisp 中的列表并非基本数据类型,它们由 cons cells 构建而成(see Cons 单元与列表类型)。Cons 单元是表示有序对的数据对象。它有两个槽位(slot),每个槽位 holds存储 或 refers to引用 某个 Lisp 对象。一个槽位称为 CAR,另一个槽位称为 CDR。(这些是传统名称;详见 Cons 单元与列表类型。)CDR 读作 “could-er”。
我们说 “这个 cons 单元的 CAR 是” 其 CAR 槽位当前存储的对象,CDR 同理。
列表是一连串链式相连的 cons 单元,每个单元指向下一个。列表中的每个元素对应一个 cons 单元。按照惯例,cons 单元的 CAR 存放列表元素,CDR 用于将列表串联起来 (CAR 与 CDR 之间的这种不对称完全是约定俗成;在 cons 单元层面,两个槽位的性质是相似的。)因此,列表中每个 cons 单元的 CDR 槽位都指向其后的下一个 cons 单元。
同样按照惯例,列表最后一个 cons 单元的 CDR 为 nil。我们把这种以 nil 结尾的结构称为 proper list正规列表5。在 Emacs Lisp 中,符号 nil 既是一个符号,也是空列表。为方便起见,符号 nil 被视为其 CAR 和 CDR 均为 nil。
因此,正规列表的 CDR 永远是正规列表。非空正规列表的 CDR 是一个去掉第一个元素后、剩余所有元素组成的正规列表。
如果列表最后一个 cons 单元的 CDR 不是 nil,我们称这种结构为 dotted list点列表,因为它的打印表示会使用点对表示法(see 点对表示法)。
还有一种可能,某个 cons 单元的 CDR 指向列表中之前的某个 cons 单元,我们称这种结构为 circular list循环列表。
在某些用途中,列表是正规、循环还是点列表并不重要。如果程序不会遍历到最后一个 cons 单元的 CDR,它就不会关心这些区别。但是,许多操作列表的函数要求输入必须是正规列表,若传入点列表会报错。大多数试图查找列表末尾的函数,在传入循环列表时会进入无限循环。你可以使用下一节介绍的函数 proper-list-p(see proper-list-p)来判断一个列表是否为正规列表。
由于绝大多数 cons 单元都用作列表的一部分,我们把所有由 cons 单元构成的结构统称为 list structure列表结构。
该函数返回 cons 单元 cons-cell 第一个槽位所引用的值。换句话说,它返回 cons-cell 的 CAR。
作为特例,若 cons-cell 为 nil,该函数返回 nil。因此,任何列表都是合法参数。若参数既非 cons 单元也非 nil,则会触发错误。
(car '(a b c))
⇒ a
(car '())
⇒ nil
该函数返回 cons 单元 cons-cell 第二个槽位所引用的值。换句话说,它返回 cons-cell 的 CDR。
作为特例,若 cons-cell 为 nil,该函数返回 nil;因此,任何列表都是合法参数。若参数既非 cons 单元也非 nil,则会触发错误。
(cdr '(a b c))
⇒ (b c)
(cdr '())
⇒ nil
该函数允许你获取 cons 单元的 CAR 值,同时避免因传入其他数据类型而触发错误。若 object 是 cons 单元,则返回其 CAR 值;否则返回 nil。这与 car 函数形成对比,car 函数在 object 非列表时会触发错误。
(car-safe object)
≡
(let ((x object))
(if (consp x)
(car x)
nil))
该函数允许你获取 cons 单元的 CDR 值,同时避免因传入其他数据类型而触发错误。若 object 是 cons 单元,则返回其 CDR 值;否则返回 nil。这与 cdr 函数形成对比,cdr 函数在 object 非列表时会触发错误。
(cdr-safe object)
≡
(let ((x object))
(if (consp x)
(cdr x)
nil))
该宏提供了一种便捷方式,可一次性查看列表的 CAR 元素并将其从列表中移除。它作用于存储在 listname 中的列表。该宏会移除列表首个元素,将 CDR 部分保存回 listname,然后返回被移除的元素。
在最简单的情况下,listname 是一个未加引号、指代列表的符号;此时该宏等价于 (prog1 (car listname) (setq listname (cdr listname)))。
x
⇒ (a b c)
(pop x)
⇒ a
x
⇒ (b c)
更通用的情况是,listname 可以是广义变量(Generalized Variable)。此时该宏会通过 setf 将值保存到 listname 中。See 广义变量。
关于向列表中添加元素的 push 宏,see 修改列表变量。
该函数返回列表 list 的第 n 个元素。元素编号从 0 开始,因此列表的 CAR 是第 0 号元素。若 list 长度小于等于 n,则返回 nil。
(nth 2 '(1 2 3 4))
⇒ 3
(nth 10 '(1 2 3 4))
⇒ nil
(nth n x) ≡ (car (nthcdr n x))
函数 elt 与之类似,但适用于任意类型的序列。出于历史原因,其参数顺序与 nth 相反。See 序列。
该函数返回列表 list 的第 n 个 CDR。换句话说,它跳过 list 的前 n 个链接,返回剩余部分。
若 n 为 0,nthcdr 返回整个 list;若 list 长度小于等于 n,nthcdr 返回 nil。
nthcdr 的别名是 drop。
(nthcdr 1 '(1 2 3 4))
⇒ (2 3 4)
(nthcdr 10 '(1 2 3 4))
⇒ nil
(nthcdr 0 '(1 2 3 4))
⇒ (1 2 3 4)
该函数返回列表 list 的前 n 个元素。本质上,它返回 nthcdr 函数会跳过的那部分 list 内容。
若列表长度小于 n,take 返回原列表 list;若 n 为 0 或负数,take 返回 nil。
通常,(append (take n list) (drop n list))
会返回一个与原列表 list 完全相等的列表。
(take 3 '(a b c d))
⇒ (a b c)
(take 10 '(a b c d))
⇒ (a b c d)
(take 0 '(a b c d))
⇒ nil
这是 take 的 “破坏性” 版本,通过修改参数的列表结构实现功能。这使其速度更快,但列表 list 的原始值可能丢失。
若列表长度小于 n,ntake 原样返回列表 list;若 n 为 0 或负数,ntake 返回 nil;否则返回截断为前 n 个元素的列表 list。
这意味着,除非确定 n 为正数,否则通常应使用其返回值,而非仅依赖截断效果。
该函数返回列表 list 的最后一个链接(link),该链接的 car 即为列表的最后一个元素。若 list 为空(null),返回 nil。若 n 非-nil,则返回倒数第 n 个链接;若 n 大于列表 list 长度,则返回整个列表 list。
该函数返回列表 list 的长度,且无触发错误或无限循环的风险。它通常返回列表中不同 cons 单元的数量;但对于循环列表,返回值仅为上限(往往偏大)。
若 list 既非 nil 也非 cons 单元,safe-length 返回 0。
当无需担心列表是循环列表时,计算列表长度最常用的方式是使用 length 函数。See 序列。
等价于 (car (car cons-cell))。
等价于 (car (cdr cons-cell))
或 (nth 1 cons-cell)。
等价于 (cdr (car cons-cell))。
等价于 (cdr (cdr cons-cell))
或 (nthcdr 2 cons-cell)。
除上述函数外,还定义了 24 个由 car 和 cdr 组合而成的函数,命名形式为 cxxxr 和 cxxxxr(每个 x 为 a 或 d)。其中 cadr、caddr、cadddr 分别用于取出列表的第二个、第三个、第四个元素。
cl-lib 库也提供了对应的函数,命名为 cl-second、cl-third、cl-fourth。
See List Functions in Common Lisp Extensions。
该函数返回移除了最后一个(或最后 n 个)元素的列表 x。若 n 大于 0,函数会复制列表以避免破坏原列表。
通常,(append (butlast x n) (last x n))
会返回与原列表 x 相等的列表。
这是 butlast 的 “破坏性” 版本,通过修改对应元素的 cdr 实现功能,而非复制列表。
列表是 Lisp 语言的核心,因此有许多函数用于构建列表。cons 是最基础的列表构建函数;但值得注意的是,在 Emacs 源代码中,list 的使用次数比 cons 更多。
该函数是构建新列表结构最基础的函数。它会创建一个新的 cons 单元,将 object1 设为 CAR,object2 设为 CDR,然后返回这个新的 cons 单元。参数 object1 和 object2 可以是任意 Lisp 对象,但 object2 通常是一个列表。
(cons 1 '(2))
⇒ (1 2)
(cons 1 '())
⇒ (1)
(cons 1 2)
⇒ (1 . 2)
cons 常用来向列表头部添加单个元素。这一操作被称为 consing the element onto the list将元素 cons 到列表上6。
例如:
(setq list (cons newelt list))
注意:本例中名为 list 的变量与下文描述的 list 函数之间无冲突 —— 任何符号都可同时作为变量和函数名使用。
该函数创建一个以 objects 为元素的列表,生成的列表始终以 nil 结尾。若未传入任何 objects,则返回空列表。
(list 1 2 3 4 5)
⇒ (1 2 3 4 5)
(list 1 2 '(3 4 5) 'foo)
⇒ (1 2 (3 4 5) foo)
(list)
⇒ nil
该函数创建一个长度为 length 的列表,其中每个元素都是 object。可将 make-list 与 make-string 对比(see 创建字符串)。
(make-list 3 'pigs)
⇒ (pigs pigs pigs)
(make-list 0 'pigs)
⇒ nil
(setq l (make-list 3 '(a b)))
⇒ ((a b) (a b) (a b))
(eq (car l) (cadr l))
⇒ t
该函数返回一个包含所有 sequences 元素的列表。sequences 可以是列表、向量、布尔向量或字符串,但最后一个参数通常应为列表。除最后一个参数外,其余所有参数都会被复制,因此不会修改任何传入的参数。(若需无复制地拼接列表,可参见 “重排列表的函数” 中的 nconc。)
更普通地,append 的最后一个参数可以是任意 Lisp 对象。该参数不会被复制或转换,而是成为新列表最后一个 cons 单元的 CDR。若最后一个参数本身是列表,则其元素会成为结果列表的元素;若最后一个参数不是列表,结果会是一个点对列表(因为其最终 CDR 不符合规范列表要求的 nil,see 列表与 Cons 单元)。
以下是 append 的使用示例:
(setq trees '(pine oak))
⇒ (pine oak)
(setq more-trees (append '(maple birch) trees))
⇒ (maple birch pine oak)
trees
⇒ (pine oak)
more-trees
⇒ (maple birch pine oak)
(eq trees (cdr (cdr more-trees)))
⇒ t
可通过框图理解 append 的工作原理。变量 trees 指向列表 (pine oak),变量 more-trees 指向列表 (maple birch pine oak)。但 trees 仍指向原始列表:
more-trees trees
| |
| --- --- --- --- -> --- --- --- ---
--> | | |--> | | |--> | | |--> | | |--> nil
--- --- --- --- --- --- --- ---
| | | |
| | | |
--> maple -->birch --> pine --> oak
空序列不会对 append 的返回值产生任何影响。因此,若最后一个参数为 nil,会强制复制前一个参数:
trees
⇒ (pine oak)
(setq wood (append trees nil))
⇒ (pine oak)
wood
⇒ (pine oak)
(eq wood trees)
⇒ nil
在 copy-sequence 函数被发明前,这曾是复制列表的常用方式。See 序列、数组与向量。
以下示例展示向量和字符串作为 append 参数的用法:
(append [a b] "cd" nil)
⇒ (a b 99 100)
将字符串转换为字符列表的方法:
(append "abcd" nil)
⇒ (97 98 99 100)
string-to-list 函数是上述操作的便捷简写。
借助 apply(see 调用函数),我们可以将一个 “列表的列表” 中的所有列表 append拼接 起来:
(apply 'append '((a b c) nil (x y z) nil))
⇒ (a b c x y z)
若未传入 sequences,返回 nil:
(append)
⇒ nil
以下示例展示最后一个参数非列表的情况:
(append '(x y) 'z)
⇒ (x y . z)
(append '(x y) [z])
⇒ (x y . [z])
第二个示例表明:若最后一个参数是序列但非列表,其元素不会成为结果列表的元素。而是像其他非列表参数一样,直接作为最终 CDR。
例外情况:若除最后一个参数外其余均为 nil,且最后一个参数非列表,则返回值为该最后一个参数本身(即此时返回值不是列表):
(append nil nil "abcd")
⇒ "abcd"
该函数返回 tree 的副本。若 tree 是 cons 单元,则创建一个新的 cons 单元(CAR 和 CDR 与原单元相同),再递归地以同样方式复制其 CAR 和 CDR。
默认情况下,若 tree 不是 cons 单元,copy-tree 直接返回 tree;但若 vectors-and-records 为非-nil,则同时复制向量和记录(并递归处理其元素)。注意 tree 参数不能包含循环引用。
该函数返回 tree 的 “flattened扁平化” 副本,即一个包含以 tree 为根的 cons 单元树中所有非-nil 终端节点(叶子节点)的列表,且叶子节点顺序与原树 tree 中一致。
(flatten-tree '(1 (2 . 3) nil (4 5 (6)) 7))
⇒(1 2 3 4 5 6 7)
该函数将 object 转换为列表返回。若 object 已是列表,则直接返回;否则返回一个包含 object 的单元素列表。
此函数常用于处理 “可能是列表、也可能不是列表” 的变量,例如:
(dolist (elem (ensure-list foo)) (princ elem))
该函数返回一个数字列表,起始值为 from,步长为 separation,终止于 to 或 to 之前。separation 可正可负,默认值为 1。
若 to 为 nil 或与 from 数值相等,返回单元素列表 (from);
若 separation 为正但 to 小于 from,或 separation 为负但 to 大于 from,返回 nil(因参数指定了空序列);
若 separation 为 0,且 to 非-nil 且与 from 数值不等,number-sequence 则触发错误(因参数指定了无限序列)。
所有参数均为数字。浮点参数需注意:浮点运算存在精度问题。例如,不同机器上 (number-sequence 0.4 0.6 0.2) 可能返回单元素列表 (0.4),而 (number-sequence 0.4 0.8 0.2) 可能返回三个元素的列表。列表的第 n 个元素通过精确公式 (+ from (* n separation)) 计算。因此若需确保 to 被包含在列表中,可将符合该精确公式的表达式作为 to 的值传入;或者,也可将 to 替换为一个略大的值(若步长 separation 为负数,则替换为一个略小的负值)。
示例:
(number-sequence 4 9)
⇒ (4 5 6 7 8 9)
(number-sequence 9 4 -1)
⇒ (9 8 7 6 5 4)
(number-sequence 9 4 -2)
⇒ (9 7 5)
(number-sequence 8)
⇒ (8)
(number-sequence 8 5)
⇒ nil
(number-sequence 5 8 -1)
⇒ nil
(number-sequence 1.5 6 2)
⇒ (1.5 3.5 5.5)
这些函数以及一个宏提供了便捷的方式来修改存储在变量中的列表。
该宏会创建一个新列表,其 CAR 为 element,CDR 为 listname 所指定的列表,并将这个新列表保存到 listname 中。在最简单的情况下,listname 是一个未加引号、指向列表的符号,此时该宏等价于 (setq listname (cons element listname))。
(setq l '(a b))
⇒ (a b)
(push 'c l)
⇒ (c a b)
l
⇒ (c a b)
更一般地,listname 可以是一个广义变量(Generalized Variable)。这种情况下,该宏等价于 (setf listname (cons element listname))。
See 广义变量。
关于从列表中移除首个元素的 pop 宏,see 访问列表元素。
有两个函数可修改作为变量值的列表。
如果元素 element 尚未是变量 symbol 原有值中的成员,此函数会将 element 加到该值的前面,从而设置变量 symbol。
无论是否更新,函数都会返回最终的列表。调用此函数前,symbol 的值最好已经是一个列表。
add-to-list 使用 compare-fn 比较 element 与列表中已有的元素;如果 compare-fn 为 nil,则使用 equal 进行比较。
通常情况下,如果添加 element,会将其加到 symbol 列表的头部;但如果可选参数 append 非空,则会加到尾部。
参数 symbol 不会被自动加引号;add-to-list 是一个普通函数,类似 set,而与 setq 不同。如果你需要,需自行给参数加引号。
此函数用于向配置变量添加元素,例如 load-path(see 库搜索)、image-load-path(see Defining Images)等。其代码中包含大量针对这类用途的特殊检查,并会输出相应警告。因此,我们不建议在 Lisp 程序中用它来构造任意列表;这种情况下请改用 push。See 修改列表变量。
当 symbol 指向词法变量时,不要使用此函数。
以下示例展示 add-to-list 的用法:
(setq foo '(a b))
⇒ (a b)
(add-to-list 'foo 'c) ;; Add c.
⇒ (c a b)
(add-to-list 'foo 'b) ;; No effect.
⇒ (c a b)
foo ;; foo was changed.
⇒ (c a b)
与 (add-to-list 'var value) 等价的表达式如下:
(if (member value var)
var
(setq var (cons value var)))
该函数会将元素 element 插入到符号 symbol 对应变量的原有值(必须是一个列表)中由 order 指定的位置,以此更新该变量的值。若 element 已是列表的成员,则会根据 order 调整它在列表中的位置。成员关系通过 eq 函数进行检测。无论变量值是否被更新,该函数都会返回最终的列表。
参数 order 通常为数字(整数或浮点数),列表元素会按照非递减的数值顺序排序。
order 也可以被省略或设为 nil:
若 element 已有对应的数值排序序号,则其序号保持不变;
若 element 无数值排序序号,则不会为其分配序号。
没有数值排序序号的元素会被放置在列表末尾,且无特定排列顺序。
若 order 为其他任意值:
若 element 已有数值排序序号,则会移除该序号;
若 element 无数值排序序号,则效果等同于 order 设为 nil。
参数 symbol 不会被隐式引用(quoted) :add-to-ordered-list 是普通函数,行为与 set 一致,而非 setq。必要时请自行为该参数添加引用符号。
排序信息存储在符号 symbol 的 list-order 属性对应的哈希表中。symbol 不能指向词法变量。
以下是展示 add-to-ordered-list 用法的示例场景:
(setq foo '()) ;; 初始化foo为空列表 ⇒ nil (add-to-ordered-list 'foo 'a 1) ;; 把a. 插入位置 1 ⇒ (a) (add-to-ordered-list 'foo 'c 3) ;; 把c插入位置 3(列表只有 1 个元素,位置 3 等价于末尾) ⇒ (a c) (add-to-ordered-list 'foo 'b 2) ;; 把b插入位置 2 ⇒ (a b c) (add-to-ordered-list 'foo 'b 4) ;; 把已存在的b移动到位置 4(末尾) ⇒ (a c b) (add-to-ordered-list 'foo 'd) ;; 无 position,把d追加到末尾 ⇒ (a c b d) (add-to-ordered-list 'foo 'e) ;; 无 position,把 e 追加到末尾。 ⇒ (a c b e d) ;; 因为d无明确位置,最大的已定义位置是 4(b),因此e被插入到位置 5 foo ;;foowas changed. ⇒ (a c b e d)
你可以通过原语(primitive)setcar 和 setcdr 修改 cons 单元的 CAR 与 CDR 内容。这些属于破坏性操作(destructive operation),因为它们会改变已有的列表结构。破坏性操作仅应作用于可变列表(mutable list)—— 即通过 cons、list 或类似操作构造的列表。通过引用(quoting)创建的列表属于程序的一部分,不应通过破坏性操作修改。See 可变性。
Common Lisp 说明: Common Lisp 使用
rplaca和rplacd函数修改列表结构;它们改变结构的方式与setcar、setcdr完全相同,但 Common Lisp 的这两个函数返回被修改的 cons 单元,而setcar和setcdr返回新的 CAR 或 CDR 值。
setcar 修改列表元素 ¶修改一个 cons 单元的 CAR 可以使用 setcar。当作用于列表时,setcar 会用另一个元素替换列表中的某个元素。
本函数将 object 存为 cons 的新 CAR,替换掉它之前的 CAR。换句话说,它修改 cons 的 CAR 槽,使其指向 object。函数返回值为 object。 示例:
(setq x (list 1 2))
⇒ (1 2)
(setcar x 4)
⇒ 4
x
⇒ (4 2)
当一个 cons 单元是多个列表共享结构的一部分时,给该 cons 设置新的 CAR 会同时改变这些列表的对应元素。示例如下:
;; 创建两个存在部分共享的列表
(setq x1 (list 'a 'b 'c))
⇒ (a b c)
(setq x2 (cons 'z (cdr x1)))
⇒ (z b c)
;; 替换共享节点的 CAR (setcar (cdr x1) 'foo) ⇒ foo x1 ; 两个列表都被改变 ⇒ (a foo c) x2 ⇒ (z foo c)
;; 替换非共享节点的 CAR (setcar x1 'baz) ⇒ baz x1 ; 只有一个列表被改变 ⇒ (baz foo c) x2 ⇒ (z foo c)
下面是变量 x1 和 x2 中两个列表共享结构的图示,这也解释了为什么替换 b 会同时改变两个列表:
--- --- --- --- --- ---
x1---> | | |----> | | |--> | | |--> nil
--- --- --- --- --- ---
| --> | |
| | | |
--> a | --> b --> c
|
--- --- |
x2--> | | |--
--- ---
|
|
--> z
下面是另一种方框图示形式,表示同样的关系:
x1:
-------------- -------------- --------------
| car | cdr | | car | cdr | | car | cdr |
| a | o------->| b | o------->| c | nil |
| | | -->| | | | | |
-------------- | -------------- --------------
|
x2: |
-------------- |
| car | cdr | |
| z | o----
| | |
--------------
修改 CDR 最底层的原语是 setcdr:
该函数将 object 存为 cons 的新 CDR,替换掉它原先的 CDR。换句话说,它修改 cons 的 CDR 槽位,使其指向 object。函数返回值为 object。
下面是一个用另一个列表替换列表 CDR 的示例。列表中除第一个元素外的所有元素都被移除,替换为另一组元素。第一个元素保持不变,因为它存放在列表的 CDR 中,不会通过 CDR 被访问到。
(setq x (list 1 2 3))
⇒ (1 2 3)
(setcdr x '(4))
⇒ (4)
x
⇒ (1 4)
通过修改列表中 cons 单元的 CDR,可以从列表中间删除元素。例如,我们通过修改第一个 cons 单元的 CDR,从列表 (a b c) 中删除第二个元素 b:
(setq x1 (list 'a 'b 'c))
⇒ (a b c)
(setcdr x1 (cdr (cdr x1)))
⇒ (c)
x1
⇒ (a c)
这是方框表示法下的结果:
--------------------
| |
-------------- | -------------- | --------------
| car | cdr | | | car | cdr | -->| car | cdr |
| a | o----- | b | o-------->| c | nil |
| | | | | | | | |
-------------- -------------- --------------
原先存放元素 b 的第二个 cons 单元仍然存在,它的 CDR 仍然是 b,但它不再属于这个列表。
通过修改 CDR 来插入新元素同样简单:
(setq x1 (list 'a 'b 'c))
⇒ (a b c)
(setcdr x1 (cons 'd (cdr x1)))
⇒ (d b c)
x1
⇒ (a d b c)
这是方框表示法下的结果:
-------------- ------------- -------------
| car | cdr | | car | cdr | | car | cdr |
| a | o | -->| b | o------->| c | nil |
| | | | | | | | | | |
--------- | -- | ------------- -------------
| |
----- --------
| |
| --------------- |
| | car | cdr | |
-->| d | o------
| | |
---------------
以下是一些通过修改组成列表的 cons 单元的 CDR,以破坏性方式重排列表的函数。这些函数之所以具有破坏性,是因为它们会 “拆解” 传入的原始列表参数,重新链接其 cons 单元,形成一个新列表并将其作为返回值。
另一个修改 cons 单元的函数可参见《将列表用作集合》章节中的 delq。
该函数返回一个包含所有 lists 中元素的列表。与 append(see 构建 cons 单元与列表)不同,nconc 不会复制这些列表;相反,它会修改每个列表的最后一个 CDR,使其指向后一个列表。lists 的最后一个不会被修改。示例如下:
(setq x (list 1 2 3))
⇒ (1 2 3)
(nconc x '(4 5))
⇒ (1 2 3 4 5)
x
⇒ (1 2 3 4 5)
由于 nconc 的最后一个参数本身不会被修改,因此像上面的示例一样使用 constant list常量列表 (如 '(4 5))是合理的。同理,最后一个参数也不必是列表:
(setq x (list 1 2 3))
⇒ (1 2 3)
(nconc x 'z)
⇒ (1 2 3 . z)
x
⇒ (1 2 3 . z)
但其他参数(除最后一个外)应当是可变列表。它们也可以是点列表(dotted list),此时其最后一个 CDR 会被替换为下一个参数:
(nconc (cons 1 2) (cons 3 (cons 4 5)) 'z)
⇒ (1 3 4 . z)
一个常见的陷阱是将常量列表用作 nconc 的非最后一个参数。如果这样做,程序的行为将是未定义的(see 自求值形式)—— 甚至可能每次运行程序时得到的结果都不同!以下是可能出现的情况(但不保证一定会发生):
(defun add-foo (x) ; 期望该函数在参数开头添加 foo
(nconc '(foo) x))
(symbol-function 'add-foo) ; 访问符号的函数单元。即获取符号绑定的函数
⇒ #f(lambda (x) [t] (nconc '(foo) x))
(setq xx (add-foo '(1 2))) ; 看起来运行正常
⇒ (foo 1 2)
(setq xy (add-foo '(3 4))) ; 出了什么问题?
⇒ (foo 1 2 3 4)
(eq xx xy)
⇒ t
(symbol-function 'add-foo)
⇒ #f(lambda (x) [t] (nconc '(foo 1 2 3 4) x))
列表可以表示数学意义上的无序集合 — 只要某个值出现在列表中,就视其为集合的元素,而忽略列表中的顺序。
求两个集合的并集可以使用 append (只要你不介意结果中出现重复元素)。
可以使用 delete-dups 或 seq-uniq 移除通过 equal 判断的重复元素。其他适用于集合的常用函数包括 memq、delq,以及基于 equal 比较的版本 member 和 delete。
Common Lisp 说明: Common Lisp 提供用于集合操作的
union(自动去重)和intersection函数。在 Emacs Lisp 中,这些功能的变体由 cl-lib 库提供。See Lists as Sets in Common Lisp Extensions。
该函数检测 object 是否为 list 的成员。如果是,memq 返回从 object 第一次出现位置开始的子列表。否则返回 nil。memq 中的字母 ‘q’ 表示它使用 eq 比较 object 与列表元素。示例:
(memq 'b '(a b c b a))
⇒ (b c b a)
(memq '(2) '((1) (2))) ; The two(2)s need not beeq. ⇒ Unspecified; might benilor((2)).
该函数破坏性地从 list 中删除所有与 object 满足 eq 的元素,并返回结果列表。delq 中的字母 ‘q’ 表示它使用 eq 比较元素,与 memq、remq 一致。
通常调用 delq 时,你应当使用其返回值,并赋值给保存原列表的变量,原因见下文说明。
delq 删除列表头部元素时,只是向后遍历列表并返回从后续位置开始的子列表。例如:
(delq 'a '(a b c)) ≡ (cdr '(a b c))
当待删元素出现在列表中间时,删除操作会修改 CDR(see 修改列表的 CDR)。
(setq sample-list (list 'a 'b 'c '(4)))
⇒ (a b c (4))
(delq 'a sample-list)
⇒ (b c (4))
sample-list
⇒ (a b c (4))
(delq 'c sample-list)
⇒ (a b (4))
sample-list
⇒ (a b (4))
请注意,(delq 'c sample-list) 会修改 sample-list,将其中第三个元素移除(拼接剔除);但 (delq 'a sample-list) 并不会剔除任何元素 —— 它仅返回一个更短的列表。切勿想当然地认为:原本存储参数 list 的变量,其元素数量会减少,或是该变量仍指向原始列表!正确的做法是:保存 delq 的返回结果,并使用这个结果。最常见的用法是将返回结果重新存回原本存储原始列表的那个变量中:
(setq flowers (delq 'rose flowers))
下面例子中,delq 试图匹配的 (list 4) 和 sample-list 里的 (4) 满足 equal 但不满足 eq:
(delq (list 4) sample-list)
⇒ (a c (4))
如果你想删除满足 equal 的元素,请使用下面的 delete。
该函数返回 list 的副本,并移除所有与 object 满足 eq 的元素。remq 中的字母 ‘q’ 表示它使用 eq 比较对象与列表 list 中的元素。
(setq sample-list (list 'a 'b 'c 'a 'b 'c))
⇒ (a b c a b c)
(remq 'a sample-list)
⇒ (b c b c)
sample-list
⇒ (a b c a b c)
该函数 memql 用于检测 object 是否为列表 list 的成员,其通过 eql 函数比较列表成员与 object,因此浮点型元素会按值进行比较。若 object 是列表成员,memql 会返回从该元素在列表 list 中首次出现位置开始的子列表;否则返回 nil。
对比 memq 函数的行为:
(memql 1.2 '(1.1 1.2 1.3)) ; 1.2 and 1.2 are eql.
⇒ (1.2 1.3)
(memq 1.2 '(1.1 1.2 1.3)) ; The two1.2s need not beeq. ⇒ Unspecified; might benilor(1.2 1.3).
以下三个函数的行为分别类似于 memq、delq 和 remq,但它们使用 equal 而非 eq 来比较元素。See 相等性谓词。
该函数 member 用于检测 object 是否为列表 list 的成员,其通过 equal 函数比较列表成员与 object。若 object 是列表成员,member 会返回从该元素在列表 list 中首次出现位置开始的子列表;否则返回 nil。
对比 memq 函数的行为:
(member '(2) '((1) (2))) ; (2) and (2) are equal.
⇒ ((2))
(memq '(2) '((1) (2))) ; The two(2)s need not beeq. ⇒ Unspecified; might benilor(2).
;; Two strings with the same contents are equal.
(member "foo" '("foo" "bar"))
⇒ ("foo" "bar")
该函数从序列 sequence 中移除所有与 object 满足 equal 相等判定的元素,并返回处理后的序列。
若 sequence 是列表,delete 与 delq 的关系,等同于 member 与 memq 的关系:它会像 member 一样,使用 equal 来比较元素与 object;当找到匹配的元素时,它会如同 delq 那样将该元素从列表中剔除。与 delq 相同,你通常应将返回值赋值给原本存储原始列表的变量,以此来使用该返回值。
若 sequence 是向量或字符串,delete 会返回 sequence 的一个副本,其中所有与 object 满足 equal 相等判定的元素均被移除。
示例:
(setq l (list '(2) '(1) '(2))) ; 定义变量l为包含三个列表的列表 (delete '(2) l) ; 从列表l中删除元素'(2)⇒ ((1)) ; 返回值为((1))l ⇒ ((2) (1)) ; 变量l的值变为((2) (1));; 若想可靠地修改变量l的值, ;; 应写成(setq l (delete '(2) l))。
(setq l (list '(2) '(1) '(2))) ; 重新定义变量l为初始列表 (delete '(1) l) ; 从列表l中删除元素'(1)⇒ ((2) (2)) ; 返回值为((2) (2))l ⇒ ((2) (2)) ; 变量l的值变为((2) (2));; 此场景下,是否重新赋值l没有区别, ;; 但为了兼容其他场景,仍建议显式赋值。
(delete '(2) [(2) (1) (2)]) ; 从向量中删除元素'(2)⇒ [(1)] ; 返回值为[(1)]
该函数是 delete 的非破坏性版本,返回序列 sequence (列表、向量或字符串)的副本,其中所有与 object equal 相等的元素均被移除。示例:
(remove '(2) '((2) (1) (2)))
⇒ ((1))
(remove '(2) [(2) (1) (2)])
⇒ [(1)]
Common Lisp 说明: GNU Emacs Lisp 中的
member、delete和remove函数源自 Maclisp,而非 Common Lisp;Common Lisp 版本的这些函数不会使用equal比较元素。
该函数的行为与 member 类似,但要求 object 是字符串,且比较时忽略字母大小写和文本编码形式的差异:大写与小写字母被视为相等,单字节字符串会先转换为多字节字符串再进行比较。
该函数会破坏性地从 list 中移除所有 equal 相等的重复元素,将结果存入 list 并返回它。
对于 list 中多个 equal 相等的同一元素,delete-dups 会保留第一个出现的元素。非破坏性的去重操作请参见 seq-uniq(see 序列)。
另可参考 “修改列表变量” 章节中的 add-to-list 函数,该函数可向存储在变量中、用作集合的列表添加元素。
association list关联列表(简称 alist)用于记录键到值的映射。它是由称为 associations关联项 的 cons 单元构成的列表:每个 cons 单元的 CAR 是 key键,CDR 是 associated value关键值。7
下面是一个关联列表(alist) 示例:键 pine 对应值 cones;键 oak 对应值 acorns;键 maple 对应值 seeds。
((pine . cones) (oak . acorns) (maple . seeds))
关联列表中的键和值都可以是任意 Lisp 对象。
例如下面这个 alist关联列表 里,符号 a 对应数值 1,字符串 "b" 对应 列表 (2 3)(作为该关联列表元素的 CDR):
((a . 1) ("b" 2 3))
有时候,把关联列表设计成将关联值存放在元素的 CDR 的 CAR 位置会更合适。下面是这类关联列表的一个示例:
((rose red) (lily white) (buttercup yellow))
这里我们将 red 视为与 rose 关联的值。这种关联列表的一个优点是,你可以在 CDR 的 CDR 中存储其他相关信息 —— 甚至是其他元素构成的列表。缺点是,你无法使用 rassq(见下文)来查找包含给定值的元素。如果这两点都不重要,那么只要在同一个关联列表中保持风格一致,选择哪种方式只是个人偏好问题。
上面同一个关联列表也可以被理解为:关联值存储在元素的 CDR 中;此时与 rose 关联的值就是列表 (red)。
关联列表常用来记录那些原本可能存放在栈中的信息,因为新的关联项可以很方便地添加到列表头部。 在关联列表中根据指定键搜索关联项时,如果存在多个匹配项,会返回第一个找到的项。
在 Emacs Lisp 中,即使关联列表中的某个元素不是 cons 单元,也 不会 报错。关联列表的搜索函数会直接忽略这类元素。而在其他许多 Lisp 方言中,这种情况会抛出错误。
注意:属性列表在多个方面与关联列表相似。属性列表的行为类似于每个键只能出现一次的关联列表。有关属性列表与关联列表的对比,see 属性列表。
该函数返回 alist 中键为 key 的第一个关联项。
若 testfn 是函数,则使用它来比较 key 与关联列表中的元素,否则使用 equal 进行比较(see 相等性谓词)。
若 testfn 是函数,它会接收两个参数:alist 中某个元素的 CAR 与 key。若经 testfn 检测后,alist 中没有任何关联项的 CAR 与 key 相等,函数返回 nil。示例:
(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
⇒ ((pine . cones) (oak . acorns) (maple . seeds))
(assoc 'oak trees)
⇒ (oak . acorns)
(cdr (assoc 'oak trees))
⇒ acorns
(assoc 'birch trees)
⇒ nil
下面是另一个示例,其中键和值都不是符号:
(setq needles-per-cluster
'((2 "Austrian Pine" "Red Pine")
(3 "Pitch Pine")
(5 "White Pine")))
(cdr (assoc 3 needles-per-cluster))
⇒ ("Pitch Pine")
(cdr (assoc 2 needles-per-cluster))
⇒ ("Austrian Pine" "Red Pine")
函数 assoc-string 与 assoc 非常相似,区别在于它会忽略字符串之间的某些差异。See 字符与字符串的比较。
该函数返回 alist 中值为 value 的第一个关联项。如果 alist 中没有任何关联项的 CDR 与 value 满足 equal 相等,则返回 nil。
rassoc 与 assoc 类似,区别在于它比较的是每个 alist 关联项的 CDR,而非 CAR。你可以将其看作反向的 assoc,即根据给定的值查找对应的键。
该函数与 assoc 类似,会返回 alist 中键为 key 的第一个关联项,但它使用 eq 进行比较。如果 alist 中没有任何关联项的 CAR 与 key 满足 eq 相等,assq 就返回 nil。这个函数比 assoc 更常用,因为 eq 比 equal 更快,并且大多数关联列表都使用符号作为键。See 相等性谓词。
(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
⇒ ((pine . cones) (oak . acorns) (maple . seeds))
(assq 'pine trees)
⇒ (pine . cones)
另一方面,在键并非符号的关联列表中,assq 通常并不适用:
(setq leaves
'(("simple leaves" . oak)
("compound leaves" . horsechestnut)))
(assq "simple leaves" leaves)
⇒ Unspecified; might be nil or ("simple leaves" . oak).
(assoc "simple leaves" leaves)
⇒ ("simple leaves" . oak)
该函数与 assq 类似。它通过将 key 与 alist 中的元素进行比较,找到第一个关联(key . value);如果找到,则返回该关联的 value。如果未找到任何关联,函数返回 default。将 key 与 alist 元素进行比较时,使用由 testfn 指定的函数,默认为 eq。
这是一个广义变量(see 广义变量),可通过 setf 用来修改值。当用它来设置值时,若可选参数 remove 为非 nil,则表示当新值与 default 满足 eql 相等时,从 alist 中移除 key 对应的关联。
该函数返回 alist 中值为 value 的第一个关联项。如果 alist 中没有任何关联项的 CDR 与 value 满足 eq 相等,则返回 nil。
rassq 与 assq 类似,区别在于它比较的是每个 alist 关联项的 CDR,而非 CAR。你可以将其看作反向的 assq,即根据给定的值查找对应的键。
示例:
(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
(rassq 'acorns trees)
⇒ (oak . acorns)
(rassq 'spores trees)
⇒ nil
rassq 函数无法查找存储在元素的 CAR 部分的 CDR 位置的值:
(setq colors '((rose red) (lily white) (buttercup yellow)))
(rassq 'white colors)
⇒ nil
在这种情况下,关联项 (lily white) 的 CDR 并不是符号 white,而是列表 (white)。如果将该关联项写成 点对(dotted pair) 形式,这一点会更加清晰:
(lily white) ≡ (lily . (white))
该函数在 alist 中搜索与 key 匹配的项。对于 alist 的每个元素:
若该元素是原子(atom),则直接将其与 key 比较;
若该元素是 cons 单元,则将其 CAR 与 key 比较。
比较方式为调用 test 函数并传入两个参数:第一个参数是元素本身(原子时)或元素的 CAR(cons 单元时),第二个参数是 key。参数按此顺序传递,目的是当你在包含正则表达式的关联列表中使用 string-match 时,能得到有效的结果(see Regular Expression Searching)。若省略 test 或其值为 nil,则使用 equal 进行比较。
如果关联列表(alist)中的某个元素按此条件与键 key 匹配,那么 assoc-default 会基于该元素返回一个值。
若该元素是一个点对单元(cons),则返回值为该元素的 CDR;
如果不是 cons 单元,返回值为 default, default 默认为 nil。
若关联列表中没有元素匹配 key,assoc-default 返回 nil。
;; 原子元素 vs cons 单元元素的直观对比
;; 原子元素的常见类型:
;; 符号(admin)、字符串("default")、数字(100)、nil 等,都是不可拆分的对象;
(setq mix-alist '(
apple ; 原子(符号)
(banana . 5) ; cons 单元(点对)
"cherry" ; 原子(字符串)
(date . 10) ; cons 单元(点对)
20 ; 原子(数字)
))
;; 匹配原子元素"cherry"
(assoc-default "cherry" mix-alist)
⇒ nil ; 原子匹配成功,返回 default(nil)
;; 匹配 cons 单元的CAR"banana"
(assoc-default 'banana mix-alist)
⇒ 5 ; cons 单元匹配成功,返回 CDR
该函数返回 alist 的二级深拷贝:它会为每个关联项创建一份新副本,这样你就可以修改新关联列表中的关联项,而不会改变原有的关联列表。
(setq needles-per-cluster
'((2 . ("Austrian Pine" "Red Pine"))
(3 . ("Pitch Pine"))
(5 . ("White Pine"))))
⇒
((2 "Austrian Pine" "Red Pine")
(3 "Pitch Pine")
(5 "White Pine"))
(setq copy (copy-alist needles-per-cluster))
⇒
((2 "Austrian Pine" "Red Pine")
(3 "Pitch Pine")
(5 "White Pine"))
(eq needles-per-cluster copy)
⇒ nil
(equal needles-per-cluster copy)
⇒ t
(eq (car needles-per-cluster) (car copy))
⇒ nil
(cdr (car (cdr needles-per-cluster)))
⇒ ("Pitch Pine")
(eq (cdr (car (cdr needles-per-cluster)))
(cdr (car (cdr copy))))
⇒ t
此示例展示了 copy-alist 如何使得修改一份副本的关联关系而不影响另一份成为可能:
(setcdr (assq 3 copy) '("Martian Vacuum Pine"))
(cdr (assq 3 needles-per-cluster))
⇒ ("Pitch Pine")
该函数会从 alist 中删除所有 CAR 与 key 满足 eq 相等 的元素,其效果大致等同于逐个使用 delq 删除这类元素。函数返回缩短后的关联列表,且通常会修改 alist 原有的列表结构。为确保结果正确,应使用 assq-delete-all 的返回值,而非直接查看 alist 保存的原始值。
(setq alist (list '(foo 1) '(bar 2) '(foo 3) '(lose 4)))
⇒ ((foo 1) (bar 2) (foo 3) (lose 4))
(assq-delete-all 'foo alist)
⇒ ((bar 2) (lose 4))
alist
⇒ ((foo 1) (bar 2) (lose 4))
该函数与 assq-delete-all 类似,区别在于它接受一个可选参数 test,这是一个用于比较 alist 中键的谓词函数。若省略该参数或其值为 nil,test 默认为 equal。与 assq-delete-all 一样,该函数通常会修改 alist 原本的列表结构。
该函数从 alist 中删除所有 CDR 与 value 满足 eq 相等 的元素。它返回缩短后的关联列表,并且通常会修改 alist 原有的列表结构。
rassq-delete-all 与 assq-delete-all 类似,区别在于它比较的是 alist 中每个关联项的 CDR,而非 CAR。
为关联列表 alist 中用作键的每个符号创建绑定,名称以点号 ‘.’ 为前缀。在需要访问同一关联列表中的多个项时,这会很有用;通过一个简单的示例就能很好地理解:
(setq colors '((rose . red) (lily . white) (buttercup . yellow)))
(let-alist colors
(if (eq .rose 'red)
.lily))
⇒ white
编译器会在编译期检查 body 部分,且仅会为那些在 body 中出现、符号名首个字符为 ‘.’(点号) 的符号创建绑定。查找这些键(keys)的操作通过 assq 完成,该 assq 调用返回值的 cdr 部分会被赋值为对应绑定的取值。
本功能支持嵌套关联列表:
(setq colors '((rose . red) (lily (belladonna . yellow) (brindisi . pink))))
(let-alist colors
(if (eq .rose 'red)
.lily.belladonna))
⇒ yellow
允许将 let-alist 嵌套使用,但内层 let-alist 中的代码无法访问外层 let-alist 所绑定的变量。
property list属性列表(简写为 plist)是由成对元素构成的列表。每一对都将一个属性名(通常是一个符号)与一个属性或值关联起来。下面是一个属性列表的示例:
(pine cones numbers (1 2 3) color "blue")
这份属性表将 pine 与 cones 关联,numbers 与 (1 2 3) 关联,color 与 "blue" 关联。属性名和属性值可以是任意 Lisp 对象,但属性名通常是符号(如本例所示)。
属性表在多种场景中使用。例如,函数 put-text-property 接受一个属性表作为参数,用于指定要应用到字符串或缓冲区中文本的文本属性及其对应值。See Text Properties。
属性表另一个重要用途是存储符号属性。每个符号都拥有一个属性列表,用于记录与该符号相关的各类信息;这些属性以属性表的形式保存。See 符号属性。
该谓词函数会在 object 是有效的属性列表时返回非-nil 值。
关联表(see 关联列表)与属性表非常相似。与关联表不同的是,属性表中键值对的顺序并不重要,因为属性名必须互不相同。
在为各种 Lisp 函数名或变量附加信息时,属性表要优于关联表。如果你的程序把所有这类信息都存放在一个关联表里,那么每次查找某个特定 Lisp 函数名或变量的关联信息时,通常都需要遍历整个列表,这可能会很慢。相比之下,如果你把同样的信息存放在函数名或变量自身的属性表中,那么每次搜索只需扫描单个属性表的长度,而这个长度通常很短。这也是变量的文档信息会被记录在名为 variable-documentation 的属性中的原因。字节编译器同样使用属性来记录那些需要特殊处理的函数。
不过,关联表也有自己的优势。根据应用场景不同,往关联表的头部添加一个关联项,可能会比更新一个属性更快。一个符号的所有属性都存放在同一个属性表里,因此不同用途之间可能出现属性名冲突。(出于这个原因,最好选择具有唯一性的属性名,例如用程序自身的变量与函数命名前缀作为属性名的开头。)关联表可以像栈一样使用:把关联项压入表的头部,之后再丢弃;这一点是属性表做不到的。
可以使用下列函数来操作属性表。它们在比较属性名时,默认都使用 eq。
该函数返回存储在属性列表 plist 中 property 属性对应的值。属性名的比较通过 predicate 完成(该参数默认值为 eq)。函数允许传入格式不规范的 plist 参数;若在 plist 中未找到 property,则返回 nil。例如:
(plist-get '(foo 4) 'foo)
⇒ 4
(plist-get '(foo 4 bad) 'foo)
⇒ 4
(plist-get '(foo 4 bad) 'bad)
⇒ nil
(plist-get '(foo 4 bad) 'bar)
⇒ nil
该函数将 value 作为属性 property 的值,存储到属性列表 plist 中。属性名的比较通过 predicate 完成(该参数默认值为 eq)。此函数可能会破坏性修改 plist,也可能构建新的列表结构而不改动原列表。函数返回修改后的属性列表,因此你可以将返回值存回原本获取 plist 的位置。例如:
(setq my-plist (list 'bar t 'foo 4))
⇒ (bar t foo 4)
(setq my-plist (plist-put my-plist 'foo 69))
⇒ (bar t foo 69)
(setq my-plist (plist-put my-plist 'quux '(a)))
⇒ (bar t foo 69 quux (a))
该废弃函数的功能与 plist-get 类似,区别在于它使用 equal 而非 eq 来比较属性名。
该废弃函数的功能与 plist-put 类似,区别在于它使用 equal 而非 eq 来比较属性名。
若 plist 中包含指定的 property,该函数返回非-nil 值。属性名的比较通过 predicate 完成(该参数默认值为 eq)。与 plist-get 不同,此函数可区分「属性不存在」和「属性值为 nil」两种情况。函数的返回值实际是 plist 中以 property 为 car(首部元素)的那个子列表(即 plist 的尾部)。
sequence(序列) 类型是另外两种 Lisp 类型的并集:列表(lists)和数组(arrays)。换句话说,任何列表都是序列,任何数组也都是序列。所有序列的共同特征是:每个序列都是元素的有序集合。
array(数组) 是一种固定长度的对象,其每个元素都对应一个存储槽位。所有元素都可在常量时间内访问。数组包含四种类型:字符串(strings)、向量(vectors)、字符表(char-tables)和布尔向量(bool-vectors)。
列表(list)是元素的序列,但它并非单一的原始对象;它由点对单元(cons cells)构成,每个元素对应一个点对单元。查找第 n 个元素需要遍历 n 个点对单元,因此离列表开头越远的元素,访问耗时越长。但列表支持动态添加或移除元素。
下图展示了这些类型之间的关系:
_____________________________________________
| |
| Sequence |
| ______ ________________________________ |
| | | | | |
| | List | | Array | |
| | | | ________ ________ | |
| |______| | | | | | | |
| | | Vector | | String | | |
| | |________| |________| | |
| | ____________ _____________ | |
| | | | | | | |
| | | Char-table | | Bool-vector | | |
| | |____________| |_____________| | |
| |________________________________| |
|_____________________________________________|
本节描述可以接受任意类型序列的函数。
如果 object 是列表、向量、字符串、布尔向量或字符表,该函数返回 t,否则返回 nil。另见下面的 seqp。
该函数返回 sequence 中的元素个数。如果参数不是序列或者是点列表(dotted list),函数会抛出 wrong-type-argument 错误;如果参数是循环列表(circular list),则抛出 circular-list 错误。对于字符表(char-table),返回的值总是比 Emacs 最大字符码大 1。
相关函数 safe-length,see Definition of safe-length。
(length '(1 2 3))
⇒ 3
(length ())
⇒ 0
(length "foobar")
⇒ 6
(length [1 2 3])
⇒ 3
(length (make-bool-vector 5 nil))
⇒ 5
另见 string-bytes,位于 Text Representations 中。
如果你需要计算字符串在显示时的宽度,应当使用 string-width(see Size of Displayed Text),而非 length。因为 length 只统计字符个数,不会考虑每个字符的实际显示宽度。
若 sequence 的长度小于 length,返回非 nil 值。如果 sequence 是一个很长的列表,使用该函数会比先计算列表长度再比较更高效。
若 sequence 的长度大于 length,返回非 nil 值。
若 sequence 的长度等于 length,返回非 nil 值。
该函数返回 sequence 中由 index 索引的元素。index 的合法取值是从 0 到序列长度减一的整数。若 sequence 是列表,超出范围的索引行为与 nth 一致,See Definition of nth。其他情况下,超出范围的索引会触发 args-out-of-range 错误。
(elt [1 2 3 4] 2)
⇒ 3
(elt '(1 2 3 4) 2)
⇒ 3
;; We use string to show clearly which character elt returns.
(string (elt "1234" 2))
⇒ "3"
(elt [1 2 3 4] 4)
error→ Args out of range: [1 2 3 4], 4
(elt [1 2 3 4] -1)
error→ Args out of range: [1 2 3 4], -1
该函数是对 aref(see 操作数组的函数)和 nth(see Definition of nth)的通用化。
该函数返回 seqr 的副本,seqr 应当是一个序列(sequence)或记录(record)。副本与原对象的类型完全相同,且包含与原对象顺序一致的相同元素。但如果 seqr 为空(例如长度为 0 的字符串或向量),该函数返回的值可能并非副本,而是与 seqr 类型相同、内容完全一致的空对象。
向副本中存入新元素不会影响原始的 seqr,反之亦然。但副本中的元素并非复制而来;它们与原对象的元素是完全相同的(通过 eq 判断为真)。因此,通过副本修改这些元素的内部内容时,对应的修改也会体现在原对象中。
若参数是带有文本属性(text properties)的字符串,则副本中的属性列表本身会被复制,不会与原字符串的属性列表共享。但属性的实际值仍为共享状态。See Text Properties。
该函数不适用于点列表(dotted lists)。尝试复制循环列表(circular list)可能会导致无限循环。
有关复制序列的其他方法,另请参见 构建 cons 单元与列表 中的 append 函数、创建字符串 中的 concat 函数,以及 向量相关函数 中的 vconcat 函数。
(setq bar (list 1 2))
⇒ (1 2)
(setq x (vector 'foo bar))
⇒ [foo (1 2)]
(setq y (copy-sequence x))
⇒ [foo (1 2)]
(eq x y)
⇒ nil
(equal x y)
⇒ t
(eq (elt x 1) (elt y 1))
⇒ t
;; Replacing an element of one sequence.
(aset x 0 'quux)
x ⇒ [quux (1 2)]
y ⇒ [foo (1 2)]
;; Modifying the inside of a shared element.
(setcar (aref x 1) 69)
x ⇒ [quux (69 2)]
y ⇒ [foo (69 2)]
该函数会创建一个新的序列,其元素为 sequence 的元素,但排列顺序完全反转。原始参数 sequence 不会 被修改。请注意,字符表(char-tables)无法被反转。
(setq x '(1 2 3 4))
⇒ (1 2 3 4)
(reverse x)
⇒ (4 3 2 1)
x
⇒ (1 2 3 4)
(setq x [1 2 3 4])
⇒ [1 2 3 4]
(reverse x)
⇒ [4 3 2 1]
x
⇒ [1 2 3 4]
(setq x "xyzzy")
⇒ "xyzzy"
(reverse x)
⇒ "yzzyx"
x
⇒ "xyzzy"
该函数会反转 sequence 中元素的排列顺序。与 reverse 函数不同的是,原始的 sequence 可能会被修改。
示例如下:
(setq x (list 'a 'b 'c))
⇒ (a b c)
x
⇒ (a b c)
(nreverse x)
⇒ (c b a)
;; The cons cell that was first is now last.
x
⇒ (a)
为避免产生混淆,我们通常会将 nreverse 函数的返回值重新存储到原本存放原始列表的同一个变量中:
(setq x (nreverse x))
以下是我们常用的示例 (a b c) 经 nreverse 函数处理后的结果,附带图形化展示:
Original list head: Reversed list: ------------- ------------- ------------ | car | cdr | | car | cdr | | car | cdr | | a | nil |<-- | b | o |<-- | c | o | | | | | | | | | | | | | | ------------- | --------- | - | -------- | - | | | | ------------- ------------
对于向量来说,操作更简单,因为你不需要使用 setq。
(setq x (copy-sequence [1 2 3 4]))
⇒ [1 2 3 4]
(nreverse x)
⇒ [4 3 2 1]
x
⇒ [4 3 2 1]
请注意,与 reverse 函数不同,本函数无法作用于字符串。尽管你可以通过 aset 函数修改字符串数据,但我们仍强烈建议你将字符串视为不可变对象 —— 即便它们本身具备可变特性。See 可变性。
该函数对 sequence 进行排序,该参数必须是列表或向量,并返回同类型的已排序序列。 该排序是稳定排序,即排序键相等的元素会保持它们原本的相对顺序。它接受下列可选关键字参数:
:key keyfunc使用 keyfunc 生成用于比较的键值。keyfunc 是一个函数,接收 sequence 中的单个元素并返回其键值。如果未提供此参数,或 keyfunc 为 nil,则默认使用 identity;即直接将元素本身作为排序键。
:lessp predicate使用 predicate 对键进行排序。predicate 是一个接收两个排序键作为参数的函数,若第一个键应排在第二个之前,则返回非 nil。如果未提供此参数,或 predicate 为 nil,则使用 value<。该函数适用于多种 Lisp 类型,通常按升序排序(see definition of value<,见下文)。
为保证一致性,所有谓词必须遵守以下规则:
:reverse flag如果 flag 为非 nil,则反转排序顺序。在默认 :lessp 谓词下,这表示按降序排序。
:in-place flag如果 flag 为非 nil,则对 sequence 进行原地排序(破坏性排序)并返回该序列。如果为 nil 或未提供此参数,则返回输入序列的排序副本,sequence 本身保持不变。原地排序速度稍快,但会丢失原序列。
如果默认行为不符合你的需求,通常提供一个新的 :key 函数,会比改用另一个 :lessp 谓词更简单、更高效。例如,考虑对这些字符串进行排序:
(setq numbers '("one" "two" "three" "four" "five" "six"))
(sort numbers)
⇒ ("five" "four" "one" "six" "three" "two")
你可以通过提供一个不同的键函数,转而按长度对这些字符串进行排序:
(sort numbers :key #'length)
⇒ ("one" "two" "six" "four" "five" "three")
请注意,得益于排序的稳定性,长度相同的字符串会保留其原始顺序。现在假设你想要按长度排序,但在长度相同时(出现并列时),再根据字符串内容来打破平局。最简单的方法是指定一个键函数,该函数能将元素转换为可按此规则排序的值。由于 value< 会按字典序对复合对象(点对、列表、向量和记录)进行排序,你可以这样做:
(sort numbers :key (lambda (x) (cons (length x) x)))
⇒ ("one" "six" "two" "five" "four" "three")
这是因为 (3 . "six") 排在 (3 . "two") 之前,依此类推。
为兼容旧版本 Emacs,sort 函数也支持以固定的双参数形式调用:
(sort sequence predicate)
其中 predicate 对应前述 :lessp 参数。使用该形式调用时,排序始终以原地方式执行。
有关更多执行排序操作的函数,see Sorting Text。关于 sort 函数的实用示例,可参见 访问文档字符串 中对 documentation 函数的说明。
该函数会在 a 按标准排序规则应排在 b 之前时返回非 nil 值;这意味着,若 b 排在 a 之前、二者相等或无排序关系,函数会返回 nil。
参数 a 和 b 必须为同一类型。具体规则如下:
< 进行比较(see definition of <)。
string-lessp 进行比较(see definition of string-lessp),符号则通过将其名称作为字符串比较来排序。
value< 比较后的结果。若其中一个序列先遍历完所有元素,则较短的序列排在较长的序列之前。
nil)会排在所有有效缓冲区之前。
nil。
Examples:
(value< -4 3.5) ⇒ t (value< "dog" "cat") ⇒ nil (value< 'yip 'yip) ⇒ nil (value< '(3 2) '(3 2 0)) ⇒ t (value< [3 2 "a"] [3 2 "b"]) ⇒ t
需要注意的是,nil 的处理方式取决于其比较对象:它会被视作符号(symbol)或空列表(empty list)二者其一:
(value< nil '(0)) ⇒ t (value< 'nib nil) ⇒ t
可比较的序列(列表、向量等)长度没有限制,但如果使用 value< 比较循环结构或深度嵌套的数据结构,该函数可能会报错并失败。
seq.el 库提供了以下额外的序列操作宏和函数,均以 seq- 为前缀。
本库中定义的所有函数都无副作用;也就是说,它们不会修改你传入的任何序列(列表、向量或字符串)。除非另有说明,返回结果的类型与输入序列的类型相同。对于接收判定函数(predicate)的那些函数,该判定函数应是只接受一个参数的函数。
seq.el 库可以进行扩展,以支持更多类型的序列式数据结构。为此,所有函数均通过 cl-defgeneric 定义。有关如何使用 cl-defgeneric 进行扩展的更多细节,see 泛型函数。
该函数返回 sequence 中指定 index 位置的元素。index 为整数,其有效值范围是从 0 到 sequence 长度减 1。对于内置序列类型,若传入超出范围的索引值,seq-elt 的行为与 elt 一致。详细说明参见 Definition of elt。
(seq-elt [1 2 3 4] 2) ⇒ 3
seq-elt 返回的位置可通过 setf 进行赋值(see setf 宏)。
(setq vec [1 2 3 4]) (setf (seq-elt vec 2) 5) vec ⇒ [1 2 5 4]
该函数返回 sequence 中包含的元素个数。对于内置序列类型,seq-length 的行为与 length 一致。See Definition of length。
若 object 是序列(列表或数组),或是通过 seq.el 通用函数定义的其他序列类型,则该函数返回非 nil 值。这是 sequencep 的可扩展变体。
(seqp [1 2]) ⇒ t
(seqp 2) ⇒ nil
该函数返回 sequence 中除前 n 个(n 为整数)元素之外的所有元素。若 n 为负数或零,则返回结果为 sequence 本身。
(seq-drop [1 2 3 4 5 6] 3) ⇒ [4 5 6]
(seq-drop "hello world" -4) ⇒ "hello world"
该函数返回 sequence 的前 n 个(n 为整数)元素。若 n 为负数或零,则返回结果为 nil。
(seq-take '(1 2 3 4) 3) ⇒ (1 2 3)
(seq-take [1 2 3 4] 0) ⇒ []
该函数按顺序返回 sequence 中的元素,在第一个使 predicate 返回 nil 的元素处停止截取(即不包含该元素)。
(seq-take-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2)) ⇒ (1 2 3)
(seq-take-while (lambda (elt) (> elt 0)) [-1 4 6]) ⇒ []
该函数按顺序返回 sequence 中的元素,从第一个使 predicate 返回 nil 的元素开始截取(包含该元素)。
(seq-drop-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2)) ⇒ (-1 -2)
(seq-drop-while (lambda (elt) (< elt 0)) [1 4 6]) ⇒ [1 4 6]
该函数返回一个列表,其中包含 sequence 被拆分后的若干子序列,每个子序列的长度最多为 length。(若 sequence 的长度并非 length 的整数倍,则最后一个子序列的长度可能小于 length。)
(seq-split [0 1 2 3 4] 2) ⇒ ([0 1] [2 3] [4])
该函数依次将 function 作用于 sequence 中的每个元素(此举通常是为了利用其副作用),并返回 sequence 本身。
该函数返回将 function 作用于 sequence 中每个元素后得到的结果,返回值为一个列表。
(seq-map #'1+ '(2 4 6)) ⇒ (3 5 7)
(seq-map #'symbol-name [foo bar])
⇒ ("foo" "bar")
该函数会将 function 应用于 sequence 的每个元素及其在 seq 中的索引,并返回应用后的结果。返回值为一个列表。
(seq-map-indexed (lambda (elt idx)
(list idx elt))
'(a b c))
⇒ ((0 a) (1 b) (2 c))
该函数会将 function 应用于 sequences 中的每组对应元素,并返回应用后的结果。function 的参数个数(参见 see subr-arity)必须与序列的数量相匹配。映射过程会在最短的序列遍历完毕时终止,返回值为一个列表。
(seq-mapn #'+ '(2 4 6) '(20 40 60)) ⇒ (22 44 66)
(seq-mapn #'concat '("moskito" "bite") ["bee" "sting"])
⇒ ("moskitobee" "bitesting")
该函数返回 sequence 中所有使 predicate 返回非 nil 值的元素组成的列表。
(seq-filter (lambda (elt) (> elt 0)) [1 -1 3 -3 5]) ⇒ (1 3 5)
(seq-filter (lambda (elt) (> elt 0)) '(-1 -3 -5)) ⇒ nil
该函数返回 sequence 中所有使 predicate 返回 nil 值的元素组成的列表。
(seq-remove (lambda (elt) (> elt 0)) [1 -1 3 -3 5]) ⇒ (-1 -3)
(seq-remove (lambda (elt) (< elt 0)) '(-1 -3 -5)) ⇒ nil
该函数返回 sequence 的一个副本,其中位于(从零开始计数的)索引 n 处的元素已被移除。返回结果的序列类型与 sequence 保持一致。
(seq-remove-at-position [1 -1 3 -3 5] 0) ⇒ [-1 3 -3 5]
(seq-remove-at-position [1 -1 3 -3 5] 3) ⇒ [1 -1 3 5]
该函数返回一个列表,包含对 sequence 中的每个元素调用 function 后得到的所有非 nil 结果。
(seq-keep #'cl-digit-char-p '(?6 ?a ?7)) ⇒ (6 7)
该函数的执行逻辑为:首先以 initial-value 和 sequence 的第一个元素为参数调用 function,接着以上一次调用的结果和 sequence 的第二个元素为参数调用 function,然后再以上一轮结果和 sequence 的第三个元素为参数调用 function,依此类推,最终返回最后一次调用 function 的结果。function 需为接收两个参数的函数。
调用 function 时会传入两个参数:initial-value(后续则为累计值)作为第一个参数,sequence 中的元素依次作为第二个参数。
若 sequence 为空序列,则不会调用 function,直接返回 initial-value。
(seq-reduce #'+ [1 2 3 4] 0) ⇒ 10
(seq-reduce #'+ '(1 2 3 4) 5) ⇒ 15
(seq-reduce #'+ '() 3) ⇒ 3
该函数会依次将 predicate 应用于 sequence 的每个元素,并返回第一个由该断言函数返回的非 nil 值。
(seq-some #'numberp ["abc" 1 nil]) ⇒ t
(seq-some #'numberp ["abc" "def"]) ⇒ nil
(seq-some #'null ["abc" 1 nil]) ⇒ t
(seq-some #'1+ [2 4 6]) ⇒ 3
该函数返回 sequence 中首个使 predicate 返回非 nil 值的元素。若没有元素匹配该断言函数,则返回 default。
需注意,若找到的元素与 default 的值完全相同,此函数会存在二义性 —— 这种情况下无法判断究竟是找到了匹配元素,还是根本没有找到任何匹配元素。
(seq-find #'numberp ["abc" 1 nil]) ⇒ 1
(seq-find #'numberp ["abc" "def"]) ⇒ nil
若将 predicate 应用于 sequence 的每一个元素后,返回结果均为非 nil 值,则该函数返回非 nil 值。
(seq-every-p #'numberp [2 4 6]) ⇒ t
(seq-every-p #'numberp [2 4 "6"]) ⇒ nil
若 sequence 为空序列,则该函数返回非 nil 值。
(seq-empty-p "not empty") ⇒ nil
(seq-empty-p "") ⇒ t
该函数返回 sequence 中使 predicate 返回非 nil 值的元素数量。
(seq-count (lambda (elt) (> elt 0)) [-1 2 0 3 -2]) ⇒ 2
该函数返回 sequence 的一个副本,该副本会根据 function 进行排序。其中 function 是一个接收两个参数的函数:若第一个参数应排在第二个参数之前,该函数需返回非 nil 值。
该函数与 seq-sort 功能类似,但在排序前,会先对 sequence 中的每个元素应用 function 进行转换。function 是一个接收单个参数的函数。
(seq-sort-by #'seq-length #'> ["a" "ab" "abc"]) ⇒ ["abc" "ab" "a"]
若 sequence 中至少有一个元素与 elt 相等,则该函数返回非 nil 值。若可选参数 function 的值为非 nil,则会使用这个接收两个参数的函数来替代默认的 equal 函数进行比较。
(seq-contains-p '(symbol1 symbol2) 'symbol1) ⇒ t
(seq-contains-p '(symbol1 symbol2) 'symbol3) ⇒ nil
该函数用于检查 sequence1 和 sequence2 是否包含完全相同的元素(元素顺序不影响判断结果)。若可选参数 testfn 的值为非 nil,则会使用这个接收两个参数的函数,替代默认的 equal 函数进行元素比较。
(seq-set-equal-p '(a b c) '(c b a)) ⇒ t
(seq-set-equal-p '(a b c) '(c b)) ⇒ nil
(seq-set-equal-p '("a" "b" "c") '("c" "b" "a"))
⇒ t
(seq-set-equal-p '("a" "b" "c") '("c" "b" "a") #'eq)
⇒ nil
该函数返回 sequence 中首个与 elt 相等的元素的(从零开始计数的)索引值。若可选参数 function 的值为非 nil,则会使用这个接收两个参数的函数,替代默认的 equal 函数进行元素比较。
(seq-position '(a b c) 'b) ⇒ 1
(seq-position '(a b c) 'd) ⇒ nil
该函数返回一个列表,其中包含 sequence 中满足以下条件的所有元素的(从零开始计数的)索引:将元素与 elt 作为参数传入 testfn 时,该函数返回非 nil 值。testfn 的默认值为 equal 函数。
(seq-positions '(a b c a d) 'a) ⇒ (0 3)
(seq-positions '(a b c a d) 'z) ⇒ nil
(seq-positions '(11 5 7 12 9 15) 10 #'>=) ⇒ (0 3 5)
该函数返回 sequence 去除重复元素后的元素组成的列表。若可选参数 function 的值为非 nil,则会使用这个接收两个参数的函数,替代默认的 equal 函数来判定元素是否重复。
(seq-uniq '(1 2 2 1 3)) ⇒ (1 2 3)
(seq-uniq '(1 2 2.0 1.0) #'=) ⇒ (1 2)
该函数返回 sequence 中从 start 到 end(均为整数)的子序列(end 的默认值为序列最后一个元素的位置)。若 start 或 end 为负数,则从 sequence 的末尾开始计数。
(seq-subseq '(1 2 3 4 5) 1) ⇒ (2 3 4 5)
(seq-subseq '[1 2 3 4 5] 1 3) ⇒ [2 3]
(seq-subseq '[1 2 3 4 5] -3 -1) ⇒ [3 4]
该函数返回一个类型为 type 的序列,该序列由 sequences 中的所有序列拼接而成。type 的可选值为:vector(向量)、list(列表)或 string(字符串)。
(seq-concatenate 'list '(1 2) '(3 4) [5 6]) ⇒ (1 2 3 4 5 6)
(seq-concatenate 'string "Hello " "world") ⇒ "Hello world"
该函数的执行逻辑为:先将 function 应用于 sequence 的每个元素并得到结果,再对该结果调用 seq-concatenate 函数,最终返回此次调用的结果。返回值为类型为 type 的序列;若 type 的值为 nil,则返回列表。
(seq-mapcat #'seq-reverse '((3 2 1) (6 5 4))) ⇒ (1 2 3 4 5 6)
该函数返回一个列表,其中包含将 sequence 的元素按长度 n 分组后得到的子序列。最后一个子序列包含的元素数量可能少于 n。n 必须为整数;若 n 为负整数或 0,则返回值为 nil。
(seq-partition '(0 1 2 3 4 5 6 7) 3) ⇒ ((0 1 2) (3 4 5) (6 7))
该函数返回一个列表,其中包含所有出现在 sequence1 或 sequence2 中的元素。返回列表中的所有元素均为唯一值(即列表中任意两个元素经比较后都不会判定为相等)。若可选参数 function 的值为非 nil,则应使用这个接收两个参数的函数来比较元素,以替代默认的 equal 函数。
(seq-union [1 2 3] [3 5]) ⇒ (1 2 3 5)
该函数返回一个列表,其中包含所有同时出现在 sequence1 和 sequence2 中的元素。若可选参数 function 的值为非 nil,则会使用这个接收两个参数的函数来比较元素,以替代默认的 equal 函数。
(seq-intersection [2 3 4 5] [1 3 5 6 7]) ⇒ (3 5)
该函数返回一个列表,其中包含所有出现在 sequence1 中但未出现在 sequence2 中的元素。若可选参数 function 的值为非 nil,则会使用这个接收两个参数的函数来比较元素,以替代默认的 equal 函数。
(seq-difference '(2 3 4 5) [1 3 5 6 7]) ⇒ (2 4)
该函数将 sequence 中的元素分组为一个关联列表(alist),该列表的键(key)是对 sequence 中的每个元素应用 function 后得到的结果。键的比较采用 equal 函数进行。
(seq-group-by #'integerp '(1 2.1 3 2 3.2)) ⇒ ((t 1 3 2) (nil 2.1 3.2))
(seq-group-by #'car '((a 1) (b 2) (a 3) (c 4))) ⇒ ((b (b 2)) (a (a 1) (a 3)) (c (c 4)))
该函数将序列 sequence 转换为类型为 type 的序列。type 可以是以下符号之一:vector(向量)、string(字符串)或 list(列表)。
(seq-into [1 2 3] 'list) ⇒ (1 2 3)
(seq-into nil 'vector) ⇒ []
(seq-into "hello" 'vector) ⇒ [104 101 108 108 111]
该函数返回 sequence(序列)中的最小元素。sequence 中的元素必须为数字或标记(marker,see Markers )。 This function returns the smallest element of sequence. The elements of sequence must be numbers or markers (see Markers).
(seq-min [3 1 2]) ⇒ 1
(seq-min "Hello") ⇒ 72
该函数返回 sequence(序列)中的最大元素。sequence 中的元素必须为数字或标记(marker)。
(seq-max [1 3 2]) ⇒ 3
(seq-max "Hello") ⇒ 111
该宏与 dolist(详见 dolist 章节)的功能类似,不同之处在于 sequence(序列)可以是列表(list)、向量(vector)或字符串(string)类型。该宏主要用于产生副作用(side-effects)场景。
该宏会将 var-sequence(变量序列)中定义的变量,绑定到 val-sequence(值序列)中对应的元素值上。这种操作被称为 解构绑定(destructuring binding)。var-sequence 中的元素本身也可以包含序列,从而支持嵌套解构。
var-sequence 序列中还可以包含 &rest 标记,其后紧跟一个变量名 —— 该变量会被绑定到 val-sequence 中剩余的所有元素上。
(seq-let [first second] [1 2 3 4] (list first second)) ⇒ (1 2)
(seq-let (_ a _ b) '(1 2 3 4) (list a b)) ⇒ (2 4)
(seq-let [a [b [c]]] [1 [2 [3]]] (list a b c)) ⇒ (1 2 3)
(seq-let [a b &rest others] [1 2 3 4] others)
⇒ [3 4]
pcase 模式提供了另一种实现解构绑定的机制,详见 使用 pcase 模式进行解构 章节。
该宏的功能与 seq-let 类似,不同之处在于:它会以 setq 的方式为变量赋值,而非像 let 那样进行变量绑定。
(let ((a nil)
(b nil))
(seq-setq (_ a _ b) '(1 2 3 4))
(list a b))
⇒ (2 4)
该函数随机返回 sequence(序列)中的一个元素。
(seq-random-elt [1 2 3 4]) ⇒ 3 (seq-random-elt [1 2 3 4]) ⇒ 2 (seq-random-elt [1 2 3 4]) ⇒ 4 (seq-random-elt [1 2 3 4]) ⇒ 2 (seq-random-elt [1 2 3 4]) ⇒ 1
若 sequence(序列)为空,则该函数会触发一个错误。
数组(array) 对象包含若干用于存放其他 Lisp 对象的槽位(slots),这些对象被称为数组的元素。访问数组中任意一个元素的时间都是常数时间。与之相对,访问列表中某个元素所需的时间与该元素在列表中的位置成正比。
Emacs 定义了四种一维数组类型:字符串(strings)(see 字符串类型)、向量(vectors)( see 向量类型)、布尔向量(bool-vectors)(see 布尔向量类型)以及 字符表(char-tables)(see 字符表类型)。
向量和字符表可以存放任意类型的元素;但字符串只能存放字符,布尔向量只能存放 t 和 nil。
这四类数组共同具备以下特性:
aref 和 aset 进行读取或修改( see 操作数组的函数)。
创建数组时,除字符表(char‑table)外,必须指定数组长度。你不能指定字符表的长度,因为其长度由字符码的范围决定。
理论上,如果你需要一个存放文本字符的数组,既可以使用字符串,也可以使用向量。但在实际使用中,我们总是选择字符串,原因有四点:
与之相对,对于键盘输入字符组成的数组(如按键序列),可能需要使用向量,因为许多键盘输入字符超出了字符串所能容纳的范围。See 读取按键序列。
本节介绍可适用于所有数组类型的函数。
如果 object 是一个数组(即向量、字符串、布尔向量或字符表),该函数返回 t。
(arrayp [a])
⇒ t
(arrayp "asdf")
⇒ t
(arrayp (syntax-table)) ;; A char-table.
⇒ t
该函数返回数组或记录 arr 中索引为 index 的元素。第一个元素的索引为 0。
(setq primes [2 3 5 7 11 13])
⇒ [2 3 5 7 11 13]
(aref primes 4)
⇒ 11
(aref "abcdefg" 1)
⇒ 98 ; ‘b’ is ASCII code 98.
另请参见 序列 章节中介绍的 elt 函数。
该函数将数组 array 中索引为 index 的元素设置为 object,并返回 object。
(setq w (vector 'foo 'bar 'baz))
⇒ [foo bar baz]
(aset w 0 'fu)
⇒ fu
w
⇒ [fu bar baz]
;; copy-sequence copies the string to be modified later.
(setq x (copy-sequence "asdfasfd"))
⇒ "asdfasfd"
(aset x 3 ?Z)
⇒ 90
x
⇒ "asdZasfd"
array 必须是可变的。See 可变性。
若 array 是字符串,而 object 不是字符,则会抛出 wrong-type-argument 错误。如有必要,该函数会将单字节字符串转换为多字节字符串,以便插入字符。
该函数将数组 array 的所有元素填充为 object,即 array 的每一个元素都会被设置为 object。该函数返回 array。
(setq a (copy-sequence [a b c d e f g]))
⇒ [a b c d e f g]
(fillarray a 0)
⇒ [0 0 0 0 0 0 0]
a
⇒ [0 0 0 0 0 0 0]
(setq s (copy-sequence "When in the course"))
⇒ "When in the course"
(fillarray s ?-)
⇒ "------------------"
若 array 为字符串且 object 并非字符,则会触发 wrong-type-argument 错误。
通用序列函数 copy-sequence(复制序列)和 length(获取长度)通常也适用于已知为数组类型的对象。See 序列。
向量(vector) 是一种通用数组,其元素可以是任意 Lisp 对象。(与之相对,字符串的元素只能是字符。See 字符串与字符。)向量在 Emacs 中有多种用途:用作按键序列(see 按键序列)、用作符号查找表(see 创建与编入符号)、作为字节编译函数表示形式的一部分(see 字节编译)等。
与其他数组一样,向量使用从零开始的索引:第一个元素的索引为 0。
向量在打印时会用方括号把元素括起来。因此,元素为符号 a、b、a 的向量会被打印为 [a b a]。你在 Lisp 输入中也可以用同样的方式书写向量。
向量与字符串、数字一样,在求值时被视为常量:对它求值的结果就是向量本身。这一过程不会对向量的元素进行求值,甚至不会检查。See 自求值形式。
用方括号书写的向量不应该通过 aset 或其他破坏性操作进行修改。See 可变性。
以下示例说明了这些规则:
(setq avector [1 two '(three) "four" [five]])
⇒ [1 two '(three) "four" [five]]
(eval avector)
⇒ [1 two '(three) "four" [five]]
(eq avector (eval avector))
⇒ t
下面是一些与向量相关的函数:
如果 object 是向量,该函数返回 t。
(vectorp [a])
⇒ t
(vectorp "asdf")
⇒ nil
该函数创建并返回一个向量,其元素为参数 objects。
(vector 'foo 23 [bar baz] "rats")
⇒ [foo 23 [bar baz] "rats"]
(vector)
⇒ []
该函数返回一个新的向量,该向量包含 length 个元素,且每个元素都初始化为 object。
(setq sleepy (make-vector 9 'Z))
⇒ [Z Z Z Z Z Z Z Z Z]
该函数返回一个新向量,其中包含 sequences 的所有元素。参数 sequences 可以是合法列表、向量、字符串或布尔向量。若未传入任何 sequences 参数,则返回空向量。
返回值要么是空向量,要么是一个新创建的非空向量 —— 该向量与任何已存在的向量都不满足 eq 相等性判断。
(setq a (vconcat '(A B C) '(D E F)))
⇒ [A B C D E F]
(eq a (vconcat a))
⇒ nil
(vconcat)
⇒ []
(vconcat [A B C] "aa" '(foo (6 7)))
⇒ [A B C 97 97 foo (6 7)]
vconcat 函数也允许将字节码函数对象作为参数。这是一项特殊功能,用于方便地访问字节码函数对象的全部内容。See 闭包函数对象。
关于其他拼接函数,可参见:映射函数 中的 mapconcat、创建字符串 中的 concat,以及 构建 cons 单元与列表 中的 append。
函数 append 还提供了一种将向量转换成包含相同元素的列表的方法:
(setq avector [1 two (quote (three)) "four" [five]])
⇒ [1 two '(three) "four" [five]]
(append avector nil)
⇒ (1 two '(three) "four" [five])
字符表与向量非常相似,区别在于它的索引是字符编码。任何不带修饰符的合法字符编码,都可以作为字符表的索引。你可以像操作普通数组一样,使用 aref 和 aset 访问字符表的元素。
此外,字符表还可以拥有 额外槽位(extra slot),用于存储与特定字符编码无关的附加数据。和向量一样,字符表在求值时是常量,并且可以存放任意类型的元素。
每个字符表都有一个 子类型(subtype),它是一个符号,主要有两个作用:
display-table 的字符表,语法表(syntax table)则是子类型为 syntax-table 的字符表。可以使用下文描述的 char-table-subtype 函数查询子类型。
char-table-extra-slots 符号属性指定(see 符号属性),其值应为 0 到 10 之间的整数。如果子类型没有该符号属性,则字符表不包含额外槽位。
字符表可以拥有一个 父表(parent),即另一个字符表。如果存在父表,那么当该字符表对某个特定字符 c 的取值为 nil 时,就会继承父表中对应字符的值。换句话说,当 char-table 自身对 c 的取值为 nil 时,(aref char-table c) 会返回其父表中的值。
字符表还可以拥有一个 默认值(default value)。如果设置了默认值,那么当字符表未为某字符指定任何非 nil 值时,(aref char-table c) 就会返回该默认值。
创建并返回一个新的字符表(char-table),其子类型为 subtype(一个符号)。表中每个元素都会初始化为 init,该参数默认值为 nil。字符表创建完成后,你无法修改其子类型。
该函数没有用于指定字符表长度的参数,因为所有字符表都预留了空间,可将任意有效的字符编码作为索引使用。
如果 subtype 拥有 char-table-extra-slots 符号属性,该属性的值会指定字符表中额外槽位(extra slots)的数量。该值必须是 0 到 10 之间的整数;否则 make-char-table 会抛出错误。若 subtype 没有 char-table-extra-slots 符号属性(see 属性列表),则该字符表不包含任何额外槽位。
如果 object 是字符表,该函数返回 t,否则返回 nil。
该函数返回 char-table 的子类型符号。
没有专门用于访问字符表中默认值的函数。要获取默认值,请使用 char-table-range(见下文)。
该函数返回 char-table 的父表。父表只能是 nil 或者另一个字符表。
该函数将 char-table 的父表设置为 new-parent。
该函数返回 char-table 的第 n 个额外槽位的内容(从 0 开始编号)。字符表的额外槽位数量由其子类型决定。
该函数将 value 存入 char-table 的第 n 个额外槽位(从 0 开始编号)。
字符表既可以为单个字符编码指定元素值,也可以为整个字符集指定一个值。
该函数返回 char-table 中为字符范围 range 指定的值。range 的取值有以下几种情况:
nil指代默认值。
指代字符 char 对应的元素(前提是 char 为有效的字符编码)。
(from . to)一个点对(cons cell)指代闭区间 ‘[from..to]’ 内的所有字符。此种情况下,函数会返回 from 所指定字符对应的值。
该函数用于在 char-table 中为字符范围 range 设置值。range 可以取以下几种值:
nil表示默认值。
t表示全部字符编码范围。
表示字符 char 对应的元素(前提是 char 为有效的字符编码)。
(from . to)一个点对单元,表示闭区间 ‘[from..to]’ 内的所有字符。
该函数会为 char-table 中每个值为非 nil 的元素调用参数 function。调用 function 时会传入两个参数:一个键(key)和一个值(value)。其中,键是可传给 char-table-range 的合法 range 参数 — 既可以是一个有效的字符,也可以是一个点对 (from . to)(用于指定一组共享同一值的字符范围);而值则是 (char-table-range char-table key) 函数的返回结果。
总体而言,传给 function 的键值对完整描述了 char-table 中存储的所有值。
该函数的返回值始终为 nil;若要让 map-char-table 的调用产生实际作用,function 需包含副作用逻辑。例如,以下是检查语法表元素的方法:
(let (accumulator)
(map-char-table
(lambda (key value)
(setq accumulator
(cons (list
(if (consp key)
(list (car key) (cdr key))
key)
value)
accumulator)))
(syntax-table))
accumulator)
⇒
(((2597602 4194303) (2)) ((2597523 2597601) (3))
... (65379 (5 . 65378)) (65378 (4 . 65379)) (65377 (1))
... (12 (0)) (11 (3)) (10 (12)) (9 (0)) ((0 8) (3)))
布尔向量(bool-vector)与普通向量(vector)非常相似,区别仅在于它仅存储 t 和 nil 两种值。如果你尝试将任何非 nil 的值存入布尔向量的某个元素中,其效果等同于在该位置存入 t。与所有数组一样,布尔向量的索引从 0 开始,且一旦创建完成,其长度便无法修改。布尔向量在求值时会被视为常量。
有若干函数是专门用于操作布尔向量的;除此之外,你也可以使用操作其他类型数组的通用函数来处理布尔向量。
创建并返回一个新的布尔向量,该向量包含 length 个元素,每个元素都会初始化为 initial 的值。
该函数创建并返回一个布尔向量,其元素为传入的参数 objects(可传入多个)。
若 object 是布尔向量,该函数返回 t;否则返回 nil。
此外,还有若干布尔向量集合操作函数,具体说明如下:
返回布尔向量 a 和 b 的 按位异或(bitwise exclusive or) 结果。若传入可选参数 c,该操作的结果会存入 c 中。所有参数都必须是长度相同的布尔向量。
返回布尔向量 a 和 b 的 按位或(bitwise or) 结果。若传入可选参数 c,该操作的结果会存入 c 中。所有参数都必须是长度相同的布尔向量。
返回布尔向量 a 和 b 的 按位与(bitwise and) 结果。若传入可选参数 c,该操作的结果会存入 c 中。所有参数都必须是长度相同的布尔向量。 Return bitwise and of bool vectors a and b. If optional argument c is given, the result of this operation is stored into c. All arguments should be bool vectors of the same length.
返回布尔向量 a 相对于 b 的 集合差(set difference) 结果。若传入可选参数 c,该操作的结果会存入 c 中。所有参数都必须是长度相同的布尔向量。
返回布尔向量 a 的 集合补(set complement) 结果。若传入可选参数 b,该操作的结果会存入 b 中。所有参数都必须是长度相同的布尔向量。
若 a 中所有值为 t 的位置在 b 中对应位置的值也为 t,则返回 t;否则返回 nil。所有参数都必须是长度相同的布尔向量。
返回布尔向量 a 中从索引 i 开始、连续等于 b 的元素个数。其中 a 是布尔向量,b 的值为 t 或 nil,i 是 a 的有效索引。
返回布尔向量 a 中值为 t 的元素总数。
其打印形式会将最多 8 个布尔值合并表示为一个字符:
(bool-vector t nil t nil)
⇒ #&4"^E"
(bool-vector)
⇒ #&0""
你可以使用 vconcat 函数像打印其他向量一样打印布尔向量:
(vconcat (bool-vector nil t nil t))
⇒ [nil t nil t]
下面是另一个创建、查看和更新布尔向量的示例:
(setq bv (make-bool-vector 5 t))
⇒ #&5"^_"
(aref bv 1)
⇒ t
(aset bv 3 nil)
⇒ nil
bv
⇒ #&5"^W"
这些结果是合理的,因为控制键 control-_ 和 control-W 对应的二进制码分别是 11111 和 10111。
环形结构(ring) 是一种固定大小的数据结构,支持插入、删除、旋转操作,以及基于模运算的索引引用和遍历。ring 包实现了高效的环形数据结构,并提供本节所列的相关函数。
注意:Emacs 中的若干环形结构(如 kill ring(删除环)和mark ring(标记环))实际上是通过简单列表实现的,并未 使用 ring 包;因此以下函数无法作用于这些环形结构。
该函数返回一个新的环形结构,可容纳 size 个对象。 size 应为整数。
若 object 是环形结构,该函数返回 t,否则返回 nil。
该函数返回 ring 环形结构的最大容量。
该函数返回 ring 环形结构当前包含的对象数量。该值绝不会超过 ring-size 函数的返回值。
该函数返回 ring 环形结构中所有对象组成的列表,按顺序排列,最新的对象排在首位。
该函数返回一个新的环形结构,是 ring 的副本。新环形结构包含与 ring 完全相同(通过 eq 判断)的对象。
若 ring 环形结构为空,该函数返回 t,否则返回 nil。
环形结构中最新的元素索引始终为 0。索引值越大,对应的元素越旧。索引值按环形结构的长度取模计算。索引 −1 对应最旧的元素,−2 对应第二旧的元素,依此类推。
该函数返回 ring 环形结构中索引 index 处的对象。index 可以是负数,也可以大于环形结构的长度。若 ring 为空,ring-ref 会触发错误。
该函数将 object 插入 ring 环形结构,使其成为最新的元素,并返回 object。
若环形结构已满,插入操作会移除最旧的元素,为新元素腾出空间。
从 ring 环形结构中移除一个对象,并返回该对象。参数 index指定要移除的元素;若该参数为 nil,则表示移除最旧的元素。若 ring 为空,ring-remove 会触发错误。
该函数将 object 插入 ring 环形结构,并将其视作最旧的元素。此函数的返回值无实际意义。
若环形结构已满,该函数会移除最新的元素,为插入的元素腾出空间。
将 ring 环形结构的容量设置为 size。若新容量更小,则环形结构中最旧的元素会被舍弃。
只要你注意不超出环形结构的容量,就可以把它当作先进先出队列(FIFO) 来使用。例如:
(let ((fifo (make-ring 5)))
(mapc (lambda (obj) (ring-insert fifo obj))
'(0 one "two"))
(list (ring-remove fifo) t
(ring-remove fifo) t
(ring-remove fifo)))
⇒ (0 t one t "two")
记录的作用是让程序员能够创建 Emacs 本身并未内置的新类型对象。它被用作 cl-defstruct 和 defclass 实例的底层表示形式。
在内部,记录对象与向量非常相似:可以用 aref 访问其槽位,用 copy-sequence 对其进行复制。但记录的第一个槽位用于存放由 type-of 返回的类型信息。此外,在当前实现中,记录最多只能有 4096 个槽位,而向量可以大得多。与数组一样,记录使用从零开始的索引:第一个槽位的下标为 0。
类型槽位应当是一个符号或类型描述符。如果是类型描述符,则会返回表示其类型的符号;详见 类型描述符。其他类型的对象则会原样返回。
记录的打印表示形式以 ‘#s’ 开头,后面跟一个表示其内容的列表。列表的第一个元素必须是记录的类型,后续元素为记录的各个槽位。
为避免与其他类型名冲突,定义新记录类型的 Lisp 程序通常应遵循所在包的命名规范来命名类型。注意:可能产生冲突的类型名,在定义该记录类型的包加载时未必已知,它们可能在之后才被加载。
记录在求值时被视为常量:对它求值的结果就是该记录本身。这一过程不会对槽位进行求值,甚至不会检查槽位。See 自求值形式。
该函数会在 object 是记录(record)类型时返回 t。
(recordp #s(a))
⇒ t
该函数用于创建并返回一个记录(record),其类型由参数 type 指定,剩余的槽位(slot)则由其余参数 objects 填充。
(record 'foo 23 [bar baz] "rats")
⇒ #s(foo 23 [bar baz] "rats")
该函数返回一个新的记录(record),其类型为 type,并包含 length 个额外的槽位(slot),且每个槽位都会初始化为 object。
(setq sleepy (make-record 'foo 9 'Z))
⇒ #s(foo Z Z Z Z Z Z Z Z Z)
要复制由记录、向量和 cons 单元(列表)构成的树形结构,请使用 copy-tree 并将其可选的第二个参数设为非 nil。See copy-tree。
哈希表是一种查找速度极快的查找表,在 “将键映射到对应值” 这一点上,有点类似于关联表(alist)(see 关联列表)。它与关联表的区别如下:
Emacs Lisp 提供了通用的哈希表(hash table)数据类型,以及一系列用于操作哈希表的函数。哈希表有专门的打印表示形式,由 ‘#s’ 开头,后面跟着一个列表,用于指定哈希表的属性与内容。See 创建哈希表。 (哈希记法,即那些没有可读表示的对象在打印时开头使用的 ‘#’ 字符,与哈希表无关。See 打印表示与读入语法。)
对象数组(obarray)也属于一类哈希表,但它们是不同类型的对象,仅用于记录已内化符号(interned symbols)。see 创建与编入符号。
创建哈希表的主要函数是 make-hash-table。
该函数根据指定的参数创建一个新的哈希表。参数应由关键字(专门识别的特定符号)与对应的值交替组成。
make-hash-table 支持多个关键字,但你真正需要了解的只有两个::test 和 :weakness。
:test test指定该哈希表的键查找比较方式。默认值为 eql,其他可选值为 eq 和 equal:
eql如果键是数字,当它们满足 equal 时视为相同,即数值相等,且同为整数或同为浮点数;否则,两个不同的对象永远不相同。
eq任意两个不同的 Lisp 对象,作为键时都视为不同。
equal如果两个 Lisp 对象按照 equal 函数判定为相等,则它们作为键时视为相同。
你可以使用 define-hash-table-test(see 定义哈希表比较方式)为 test 定义更多可选的比较方式。
:weakness weak哈希表的 “弱引用(weakness)” 属性用于指定:哈希表中键(key)或值(value)的存在,是否会阻止它们被垃圾回收(garbage collection)。
参数 weak 的取值必须是 nil、key、value、key-or-value、key-and-value 之一,其中 t 是 key-and-value 的别名。若 weak 设为 key,则哈希表不会阻止其键被垃圾回收(前提是这些键在其他地方无引用);当某个键被回收时,对应的键值对会从哈希表中移除。
若 weak 设为 value,则哈希表不会阻止其值被垃圾回收(前提是这些值在其他地方无引用);当某个值被回收时,对应的键值对会从哈希表中移除。
若 weak 设为 key-and-value 或 t,则只有当键和值都处于 “存活” 状态时,对应的键值对才会被保留。因此,哈希表既不会保护键、也不会保护值免于垃圾回收;只要键或值任意一方被回收,该键值对就会被移除。
如果 weak 为 key-or-value,那么键或值其中任意一个存活,就能保留该键值对。因此,只有当键和值都将被垃圾回收时(若非因为弱哈希表的引用),对应的键值对才会从哈希表中移除。
weak 的默认值为 nil,此时哈希表中的所有键和值都会被保护,不会被垃圾回收。
:size size该参数用于提示你计划在哈希表中存放多少个键值对。如果你知道大致数量,通过该参数指定可以略微提升效率;但由于哈希表内存是自动管理的,这种速度提升通常并不显著。
你还可以使用哈希表的打印表示形式来创建哈希表。只要指定哈希表中的每个元素都有合法的读取语法(see 打印表示与读入语法),Lisp 读取器就能解析这种打印表示。
例如,下面的表达式定义了一个哈希表,其中包含键 key1 和 key2(均为符号),分别对应值 val1(符号)和 300(数字)。
#s(hash-table data (key1 val1 key2 300))
需要注意的是,在 Emacs Lisp 代码中使用这种方式时,是否会创建新的哈希表是未定义行为。如果你希望创建新的哈希表,应当始终使用 make-hash-table 函数(see 自求值形式)。
哈希表的打印表示形式以 ‘#s’ 开头,其后紧跟一个以 ‘hash-table’ 为首元素的列表。列表的其余部分由零个或多个 “属性 - 值” 对组成,用于指定哈希表的属性和初始内容。这些属性与值会按字面量读取。合法的属性名包括 test、weakness 和 data:其中 data 属性应是一个包含键值对的列表,用于设定哈希表的初始内容;其余属性的含义与上文所述 make-hash-table 函数的对应关键字(:test 和 :weakness)完全一致。
注意:你不能直接指定初始内容中包含无读取语法的对象(例如缓冲区、窗口框架)的哈希表。这类对象可以在哈希表创建之后再添加进去。
本节介绍用于在哈希表中访问和存储键值对的函数。一般情况下,任意 Lisp 对象都可以作为哈希表的键,除非比较方法本身有限制;任意 Lisp 对象也都可以作为值。
该函数在 table 中查找 key,并返回其关联的 value;如果 key 在 table 中不存在,则返回 default。
该函数在 table 中为 key 建立关联,值为 value。如果 key 已存在于 table 中,则 value 会替换掉旧的值。本函数总是返回 value。
该函数从 table 中移除 key 对应的键值对(如果存在)。如果 key 不存在,remhash 不做任何操作。
Common Lisp 注意事项: 在 Common Lisp 中,若 remhash 实际移除了一个键值对,则返回非 nil 值;否则返回 nil。而在 Emacs Lisp 中,remhash 始终返回 nil。
该函数会移除哈希表 table 中的所有键值对,使其变为空表。这一操作也被称为 清空(clearing) 哈希表。clrhash 返回清空后的 table。
该函数会对 table 中的每一个键值对调用一次 function。函数 function 需接收两个参数 — table 中的一个 key(键),以及其对应的 value(值)。maphash 的返回值为 nil。
允许 function 调用 puthash 为当前 key 设置新值,或调用 remhash 移除当前 key;但不允许在 function 中向 table 添加、移除或修改其他键值对。
你可以通过 define-hash-table-test 定义新的键查找方法。要使用该功能,你需要理解哈希表的工作原理,以及 哈希码(hash code) 的含义。
可以从概念上把哈希表看作一个拥有很多位置的大型数组,每个位置都能存放一个键值对。查找键时,gethash 首先根据键计算出一个整数,即哈希码。它会将该整数对数组长度取模,得到数组中的下标。然后在该位置查找,必要时再检查附近的位置,判断是否找到了目标键。
因此,要定义一种新的键查找方式,你需要同时指定两个函数:一个根据键计算哈希码的函数;一个直接比较两个键是否相等的函数。这两个函数必须保持一致:也就是说,如果两个键比较结果相等,那么它们的哈希码也必须相同。此外,由于这两个函数可能在任意时刻被调用(例如被垃圾回收器调用),它们应当无副作用、执行迅速,并且行为只依赖于键不会改变的属性。
该函数定义一个名为 name 的新哈希表比较规则。
用这种方式定义好 name 之后,你就可以在 make-hash-table 中把它用作 test 参数。这样一来,该哈希表就会使用 test-fn 来比较键,并用 hash-fn 从键计算哈希码。
函数 test-fn 应接收两个参数(两个键),如果认为它们相同,则返回非 nil。
函数 hash-fn 应接收一个参数(一个键),并返回一个整数作为该键的哈希码。为了达到较好的效果,该函数应使用完整的定长整数范围来生成哈希码,包括负整数。
指定的这两个函数会被存放在 name 的属性列表中,属性名为 hash-table-test;属性值的形式为 (test-fn hash-fn)。
函数 test-fn 应接受两个参数(两个键),如果认为这两个键相同,则返回非 nil。
函数 hash-fn 应接受一个参数(一个键),并返回一个整数作为该键的哈希码。为了获得良好效果,该函数应使用完整的 fixnum(定长整数)范围来生成哈希码,包括负整数。
指定的这两个函数会被存放在 name 的属性列表中,属性名为 hash-table-test;属性值的格式为 (test-fn hash-fn)。
该函数为 Lisp 对象 obj 返回一个哈希码。这是一个反映 obj 内容及其指向的其他 Lisp 对象的整数。
如果两个对象 obj1 和 obj2 满足 equal,那么 (sxhash-equal obj1) 和 (sxhash-equal obj2) 是相同的整数。
如果两个对象不满足 equal,sxhash-equal 返回的值通常不同,但并非绝对。sxhash-equal 被设计为速度适中(因为它用于哈希表索引),因此不会深度递归遍历嵌套结构。此外,极少数情况下,你可能会遇到两个看起来不同的简单对象,却被 sxhash-equal 算出相同的哈希码。因此,通常不能用 sxhash-equal 来检测一个对象是否发生了变化。
Common Lisp 注意: 在 Common Lisp 中,类似的函数名为 sxhash。Emacs 提供了这个名字,作为 sxhash-equal 的兼容别名。
该函数为 Lisp 对象 obj 返回一个哈希码。其返回结果反映的是 obj 的标识(identity),而非其内容。
如果两个对象 obj1 和 obj2 满足 eq(标识相等),那么 (sxhash-eq obj1) 和 (sxhash-eq obj2) 会返回相同的整数。
该函数为 Lisp 对象 obj 返回一个适用于 eql 比较的哈希码。换句话说,它反映的是 obj 的标识,但有一个例外:当对象是大整数(bignum)或浮点数时,哈希码会根据其数值生成。
如果两个对象 obj1 和 obj2 满足 eql,那么 (sxhash-eql obj1) 和 (sxhash-eql obj2) 会返回相同的整数。
以下示例创建了一个哈希表,其键为字符串,且字符串的比较是大小写不敏感的。
(defun string-hash-ignore-case (a) (sxhash-equal (upcase a))) (define-hash-table-test 'ignore-case 'string-equal-ignore-case 'string-hash-ignore-case) (make-hash-table :test 'ignore-case)
下面是你可以如何定义一个与预定义比较规则 equal 等价的哈希表比较方式。键可以是任意 Lisp 对象,看起来内容相等的对象会被视为同一个键。
(define-hash-table-test 'contents-hash 'equal 'sxhash-equal) (make-hash-table :test 'contents-hash)
Lisp 程序 不应该 依赖哈希码在不同 Emacs 会话之间保持不变,因为哈希函数的实现会使用对象存储的某些细节,这些细节在不同会话、不同架构之间可能发生变化。
以下是一些用于操作哈希表的其他函数。
若 table 是哈希表对象,则返回非 nil 值。
该函数创建并返回 table 的一个副本。仅哈希表本身会被复制 — 键和值均为共享引用。
该函数返回 table 中实际存在的条目数量。
该函数返回创建 table 时指定的 test 参数值(该参数用于定义哈希计算和键比较的方式)。参见 make-hash-table(see 创建哈希表)。
该函数返回为哈希表 table 指定的 weak 参数值(弱引用属性)。
该函数返回 table 当前的内存分配大小。由于哈希表的内存分配是自动管理的,该值通常无需关注。
一个 符号(symbol) 是一个具有唯一名称的对象。本章介绍符号、符号的组成部分、符号的属性列表,以及符号的创建和编入符号表(intern)方式。其他独立章节会介绍符号作为变量和函数名的使用场景;参见 变量 和函数。关于符号的精确读取语法,参见符号类型。
你可以使用 symbolp 函数检测任意一个 Lisp 对象是否为符号:
若 object 为符号,该函数返回 t,否则返回 nil。
每个符号都有四个组成部分(或称 “单元(cells)”),每个部分都引用另一个对象:
符号的名称。
符号作为变量时的当前值。
符号的函数定义。它也可以存放一个符号、一个键盘映射表或一个键盘宏。
符号的属性列表。
打印名单元始终存放一个字符串,且不可修改。其他三个单元则可以被设置为任意 Lisp 对象。
打印名单元存放的是作为符号名称的字符串。由于符号是通过名称来文本表示的,因此不能存在两个同名符号。Lisp 读取器会保证这一点:每次读取一个符号时,它都会先查找是否已存在指定名称的符号,再决定是否新建。要获取符号的名称,可以使用函数 symbol-name(see 创建与编入符号)。不过,尽管每个符号都只有唯一的 打印名(print name),但仍然可以通过名为「简写 “shorthands”)」的不同别名来引用同一个符号(see 简写符号)。
值单元存放符号作为变量的值,也就是当符号本身被当作 Lisp 表达式求值时得到的结果。关于值如何被设置与获取,包括 局部绑定(local bindings) 和 作用域规则(scoping rules) 等复杂细节,See 变量。大多数符号的值可以是任意 Lisp 对象,但某些特殊符号的值不可修改,包括 nil 和 t,以及所有以 ‘:’ 开头的符号(这类符号称为 关键字(keywords))。See 永不改变的变量。
函数单元存放符号的函数定义。我们常说 “foo 函数”,实际指的是存放在 foo 的函数单元中的函数;仅在必要时我们才会明确区分这两者。通常,函数单元用于存放函数(see 函数)或宏(see 宏)。不过,它也可以用来存放符号(see 符号函数间接引用)、键盘宏(see 键盘宏)、键盘映射表(see 按键映射)或自动加载对象(see 自动加载)。要获取符号的函数单元内容,可使用函数 symbol-function(see 访问函数单元内容)。
属性列表单元通常应存放格式正确的属性列表。要获取符号的属性列表,可使用函数 symbol-plist。see 符号属性。
值单元可以是 未绑定(void) 状态,意味着该单元没有引用任何对象。(这既不等同于存放符号 void,也不等同于存放符号 nil。)访问一个处于未绑定状态的值单元会触发错误,例如 ‘Symbol's value as variable is void’(符号作为变量的值未绑定)。
由于每个符号都拥有独立的值单元和函数单元,因此变量名与函数名不会冲突。例如,符号 buffer-file-name 既拥有一个值(当前缓冲区正在访问的文件名),同时也拥有一个函数定义(一个返回该文件名的原语函数):
buffer-file-name
⇒ "/gnu/elisp/symbols.texi"
(symbol-function 'buffer-file-name)
⇒ #<subr buffer-file-name>
定义(definition) 是一类特殊的 Lisp 表达式,用于表明你打算以某种特定方式使用一个符号。它通常会为符号指定一种用途下的值或含义,同时附带该用法的文档说明。因此,当你将一个符号定义为变量时,可以为该变量提供初始值以及对应的文档说明。
defvar 和 defconst 是用于将符号定义为 全局变量(global variable) 的特殊形式 —— 全局变量可在 Lisp 程序的任意位置访问。关于变量的详细说明,See 变量,可使用 defcustom 宏,它内部会调用 defvar 来完成工作(see 自定义设置)。
理论上,你可以使用 setq 为任意符号赋予变量值,无论该符号是否事先被定义为变量。但是,对于你要使用的每个全局变量,都应当编写对应的变量定义;否则,当在启用词法作用域的环境中运行时,你的 Lisp 程序可能无法正常执行(see Scoping 变量绑定的作用域规则)。
defun 将符号定义为函数 —— 它会创建一个 lambda 表达式,并将其存储到该符号的函数单元中。这个 lambda 表达式也就成为了该符号的函数定义。(“函数定义(function definition)” 这一术语指代函数单元中存储的内容,其由来正是 defun 为符号赋予了作为函数的定义。)defsubst 和 defalias 是另外两种定义函数的方式。See 函数。
defmacro 将符号定义为宏。它会创建一个宏对象,并将其存储到该符号的函数单元中。请注意,一个符号可以是宏或函数,但不能同时兼具两者身份—— 因为宏定义和函数定义都存储在函数单元中,而该单元在任意时刻只能存放一个 Lisp 对象。参见 See 宏。
如前所述,Emacs Lisp 允许同一个符号既被定义为变量(例如通过 defvar),又被定义为函数或宏(例如通过 defun)。这类定义不会产生冲突。
这些定义同时也为编程工具提供指引。例如,C-h f 和 C-h v 命令会生成帮助缓冲区,其中包含指向对应变量、函数或宏定义的链接。See Name Help in The GNU Emacs Manual。
要理解 GNU Emacs Lisp 中符号是如何创建的,你必须了解 Lisp 是如何读取它们的。Lisp 必须保证:在同一上下文里,每次读取相同字符序列时,都能得到同一个符号。如果做不到这一点,就会造成彻底的混乱。
表当 Lisp 读取器在代码中遇到一个引用符号的名称时,它会在一张名为 obarray(符号表) 的表中查找该名称,以找到程序员所指的符号。符号表是一个以名称为索引、存放符号的无序容器。
Lisp 读取器还会处理 “简写(shorthands)”。如果程序员提供了简写,即便源代码中没有写出符号的完整名称,读取器也能找到对应的符号。See 简写符号。
如果找到了具有目标名称的符号,读取器就会使用该符号。如果符号表中不存在该名称的符号,读取器会创建一个新符号并将其添加到符号表中。查找或添加某个名称的符号这一过程称为 编入(intern) 该符号,经过这一过程的符号称为 已编入符号(interned symbol)。
编入操作保证了每个符号表中,任意名称只对应唯一的一个符号。其他同名符号可以存在,但不会出现在同一个符号表里。因此,只要使用同一个符号表进行读取,相同的名称就总会得到相同的符号。
编入操作通常在读取器中自动完成,但有时其他程序也需要主动执行。例如,M-x 命令通过小缓冲区以字符串形式获取命令名后,会将该字符串编入,从而得到对应名称的已编入符号。再举一个例子,一个假想的电话簿程序可以将每个查询到的人名作为符号编入,即便该符号表中原本不存在,这样就可以把信息附加到这个新符号上,比如上次被查询的时间。
没有任何一个符号表包含所有符号;事实上,有些符号不属于任何符号表。它们被称为 未编入符号(uninterned symbols)。未编入符号同样拥有其他符号所具备的四个单元;但是,访问它的唯一途径是:在其他对象中找到它,或是通过某个变量的值获取它。未编入符号在生成 Lisp 代码时有时很有用,详见下文。
Common Lisp 注意: 与 Common Lisp 不同,Emacs Lisp 不支持将同一个名称在多个不同的 “包(package)” 中编入,从而创建同名但属于不同包的多个符号。Emacs Lisp 提供了一套名为 “简写(shorthands)” see 简写符号 的命名空间机制。
该函数创建并返回一个新的符号表(obarray)。可选参数 size 可用于指定该符号表预计容纳的符号数量,但由于符号表会根据需要自动扩容,因此这个参数几乎不会带来任何实际收益。
如果 object 是一个符号表(obarray),该函数返回 t,否则返回 nil。
下述大部分函数会接收一个名称(字符串)作为参数,有时还会接收一个符号表作为参数。若传入的名称不是字符串,或传入的符号表并非合法的符号表对象,将触发 wrong-type-argument(参数类型错误)异常。
该函数返回作为 symbol 名称的字符串。例如:
(symbol-name 'foo)
⇒ "foo"
警告: 切勿修改该函数返回的字符串。这样做可能会导致 Emacs 功能异常,甚至使 Emacs 崩溃。
创建一个未注册符号(uninterned symbol)在生成 Lisp 代码时十分实用,因为在你生成的代码中,将未注册符号用作变量时,不会与其他 Lisp 程序中使用的任何变量产生命名冲突。
该函数返回一个新分配的未注册符号,其名称为name(参数必须是字符串类型)。该符号的变量值和函数定义均为未定义(void)状态,其属性列表为 nil。在下方示例中,sym 的值与 foo 并非 eq(全等),因为前者是一个独立的未注册符号,只是名称同样为 ‘foo’ 而已。
(setq sym (make-symbol "foo"))
⇒ foo
(eq sym 'foo)
⇒ nil
该函数通过 make-symbol 创建并返回一个符号,其名称的生成规则为:将 gensym-counter(gensym 计数器)的值追加到 prefix(前缀)之后,并将该计数器自增。这一机制能保证对该函数的任意两次调用,都不会生成同名符号。若未指定前缀,默认使用 "g"。
为避免因意外注册(intern)生成代码的打印表示形式而引发问题(see 打印表示与读入语法),建议使用 gensym 而非 make-symbol。
该函数返回名称为 name 的已注册符号。若符号表 obarray 中不存在该符号,intern 会创建一个新符号,将其加入该符号表后返回。若省略 obarray 参数,则使用全局变量 obarray 的值作为默认符号表。
(setq sym (intern "foo"))
⇒ foo
(eq sym 'foo)
⇒ t
(setq sym1 (intern "foo" other-obarray))
⇒ foo
(eq sym1 'foo)
⇒ nil
Common Lisp 注: 在 Common Lisp 中,你可以将一个已存在的符号注册到符号表(obarray)中。而在 Emacs Lisp 中无法这样做,因为
intern的参数必须是字符串,而不能是符号。
该函数返回符号表 obarray 中名称为 name 的符号;若 obarray 中不存在该名称的符号,则返回 nil。因此,你可以使用 intern-soft 来检测指定名称的符号是否已被注册(intern)。若省略 obarray 参数,则使用全局变量 obarray 的值作为默认符号表。
参数 name 也可以是一个符号;这种情况下,如果该符号已注册在指定的符号表中,函数会返回该符号(name),否则返回 nil。
(intern-soft "frazzle") ; No such symbol exists. ⇒ nil (make-symbol "frazzle") ; Create an uninterned one. ⇒ frazzle
(intern-soft "frazzle") ; That one cannot be found.
⇒ nil
(setq sym (intern "frazzle")) ; Create an interned one.
⇒ frazzle
(intern-soft "frazzle") ; That one can be found!
⇒ frazzle
(eq sym 'frazzle) ; And it is the same one.
⇒ t
该变量是供 intern 和 read 函数使用的标准符号表(obarray)。
该函数会对符号表 obarray 中的每一个符号调用一次 function 函数,执行完成后返回 nil。若省略 obarray 参数,则默认使用全局变量 obarray 的值(即存储普通符号的标准符号表)。
(setq count 0)
⇒ 0
(defun count-syms (s)
(setq count (1+ count)))
⇒ count-syms
(mapatoms 'count-syms)
⇒ nil
count
⇒ 1871
可参见 访问文档字符串(访问文档)章节中关于 documentation 函数的说明,其中包含另一个使用 mapatoms 函数的示例。
该函数将符号 symbol 从符号表 obarray 中移除。若 symbol 并未实际存在于该符号表中,unintern 不会执行任何操作。若 obarray 为 nil,则使用当前的符号表。
如果你传入的不是符号,而是一个字符串作为 symbol 参数,该字符串会被视作符号名称。此时 unintern 会删除符号表中名称为此字符串的符号(若存在);若不存在该名称的符号,unintern 不会执行任何操作。
若 unintern 成功删除了符号,返回 t;否则返回 nil。
该函数会将符号表 obarray 中的所有符号全部移除。
一个符号可以拥有任意数量的 符号属性(symbol properties),这些属性可用于记录与该符号相关的各类附加信息。例如,当一个符号拥有一个值为非 nil 的 risky-local-variable 属性时,表示该符号所命名的变量是一个有风险的文件局部变量(see 文件局部变量)。
每个符号的属性及其属性值,都存储在该符号的属性列表单元(property list cell)中(see 符号的组成), 以属性列表(property list)的形式保存(see 属性列表)。
以下函数可用于访问符号的属性。
该函数返回 symbol(符号)的属性列表中,名为 property(属性名)的属性对应的值。若不存在该属性,则返回 nil。因此,属性值为 nil 与属性不存在这两种情况无法区分。
属性名 property 会通过 eq 函数与已有的属性名进行比较,因此任意对象都可以作为合法的属性名。
可参见 put 函数的说明以查看示例。
该函数将值 value 存入 symbol(符号)的属性列表中,并关联到属性名 property 之下;若该属性名已存在,则覆盖其原有值。put 函数的返回值为 value。
(put 'fly 'verb 'transitive)
⇒'transitive
(put 'fly 'noun '(a buzzing little bug))
⇒ (a buzzing little bug)
(get 'fly 'verb)
⇒ transitive
(symbol-plist 'fly)
⇒ (verb transitive noun (a buzzing little bug))
该函数返回 symbol(符号)的属性列表。
该函数将 symbol(符号)的属性列表设置为 plist。通常情况下,plist 应当是格式规范的属性列表,但这一要求不会被强制校验。该函数的返回值为 plist。
(setplist 'foo '(a 1 b (2 3) c nil))
⇒ (a 1 b (2 3) c nil)
(symbol-plist 'foo)
⇒ (a 1 b (2 3) c nil)
对于专用符号表(special obarrays)中的符号(并非用于普通用途),以非标准方式使用其属性列表单元是合理的;事实上,*缩写机制(abbrev mechanism) 正是这么做的(see Abbrevs and Abbrev Expansion)。
你可以通过 setplist 和 plist-put 来定义 put,示例如下:
(defun put (symbol prop value)
(setplist symbol
(plist-put (symbol-plist symbol) prop value)))
该函数与 get 完全相同,区别在于:如果 symbol 是某个函数别名,它会去查找实际函数对应符号的属性列表。See 定义函数。
如果可选参数 autoload 为非 nil,且 symbol 是自动加载函数,该函数会尝试自动加载它,因为自动加载可能会设置该符号的 property。如果 autoload 为符号 macro,则仅当 symbol 是自动加载宏时,才尝试自动加载。
该函数将 function 的 property 属性设为 value。function 应当是一个符号。
在设置函数属性时,推荐使用此函数,而非直接调用 put,因为未来它可以支持将旧属性自动映射到新属性。
下面列出在 Emacs 中用于特殊用途的标准符号属性。在下表中,凡是提到 “指定函数(the named function)”,均指名称为对应符号的函数;“指定变量(the named variable)” 等表述同理。
:advertised-binding该属性的值用于指定:在显示文档时,指定函数所推荐使用的按键绑定。 See 文档中的按键绑定替换。
char-table-extra-slots若该属性的值非 nil,则表示指定的字符表类型中额外槽位的数量。See 字符表。
customized-faceface-defface-specsaved-facetheme-face这些属性用于记录一个外观(face) 的标准、已保存、已自定义和主题面规格。请勿直接设置它们;它们由 defface 及相关函数管理。See Defining Faces。
customized-valuesaved-valuestandard-valuetheme-value这些属性用于记录可自定义变量的标准值、已保存值、已自定义但未保存值以及主题值。请勿直接设置它们;它们由 defcustom 及相关函数管理。See 定义自定义变量。
definition-name该属性用于在无法通过源码文本搜索找到符号定义时,定位该符号在源代码中的定义。例如,define-derived-mode(see 定义派生模式)可能会隐式定义某个模式专用的函数或变量;或者你的 Lisp 程序会在运行时通过调用 defun 来动态定义函数(see 定义函数)。
在这些及类似场景中,符号的 definition-name 属性应当指向另一个符号:该符号的定义可以通过文本搜索找到,并且其代码负责定义原始符号。在 define-derived-mode 的例子中,由它定义的函数和变量的此属性值,应当设为对应的模式符号。
Emacs 的帮助命令(如 C-h f,see Help in The GNU Emacs Manual)会利用该属性,在 *Help* 缓冲区的文档里通过按钮直接跳转到符号的定义位置。
disabled若该属性的值为非 nil,则指定的函数作为命令时是被禁用的。see 禁用命令。
face-documentation该属性的值存储指定外观(face)的文档字符串。它由 defface 自动设置。see Defining Faces。
history-length若该属性值非 nil,则指定对应历史列表变量的小缓冲区(minibuffer)历史最大长度。
See 迷你缓冲历史。
interactive-form该属性值为对应函数的交互式代码(interactive form)。通常不应直接设置此属性;请改用 interactive 特殊表达式。See 交互式调用。
menu-enable该属性值是一个表达式,用于判断对应菜单项在菜单中是否应处于启用状态。See 简单菜单项。
mode-class若值为 special,则对应主模式为特殊主模式。See 主模式编码规范。
permanent-local若值非 nil,则对应变量为缓冲区局部变量,且在切换主模式时其值不会被重置。
See 创建与删除缓冲区局部绑定。
permanent-local-hookIf the value is non-nil, the named function should not be
deleted from the local value of a hook variable when changing major
modes. See 设置钩子.
pure ¶若属性值非 nil,则表示该函数被视为纯函数(see 什么是函数?)。使用常量参数的调用可在编译期执行求值,这可能会将运行时错误提前到编译时出现。不要与纯存储(pure storage)混淆(see Pure Storage)。
risky-local-variable若属性值非 nil,则表示该变量作为文件局部变量时被视为有风险。see 文件局部变量。
safe-function若属性值非 nil,则表示该函数通常可安全执行求值。see 判断一个函数是否可以安全调用。
safe-local-eval-function若属性值非 nil,则表示该函数可以在文件局部求值表达式中安全调用。see 文件局部变量。
safe-local-variable该属性的值指定一个函数,用于判断指定变量的文件局部值是否安全。See 文件局部变量。由于加载文件时会用到该值,因此这个函数应当高效,且最好不会为了判断安全性而触发加载其他库(例如不应是自动加载函数)。
side-effect-free ¶非 nil 的值表示该函数无副作用(see 什么是函数?),因此字节编译器可以忽略不使用返回值的调用。如果该属性的值为 error-free,字节编译器甚至可以直接删除这类未使用的调用。除了字节编译器优化,该属性还用于判断函数安全性(see 判断一个函数是否可以安全调用)。
important-return-value ¶非 nil 的值会让字节编译器对调用该函数但不使用其返回值的代码发出警告。这对于那些忽略返回值很可能是错误的函数非常有用。
undo-inhibit-region若值非 nil,则在该函数执行后立即调用 undo 时,撤销操作不会被限制在当前激活区域内。See Undo。
variable-documentation若值非 nil,该属性用于指定对应变量的文档字符串。它由 defvar 及相关函数自动设置。See Defining Faces。
符号 简写符号(shorthands),有时也被称作 “重命名符号(renamed symbols)”,是出现在 Lisp 源码中的符号形式。它们与普通符号形式完全一样,唯一的区别是:当 Lisp 读取器遇到它们时,会生成具有不同且通常更长的 打印名(print name) 的符号(see 符号的组成)。
可以把简写符号理解为对目标符号完整名称的 缩写,这一理解很有用。尽管如此,不要将简写符号与缩写(Abbrev)系统混淆(see Abbrevs and Abbrev Expansion)。
简写符号让 Emacs Lisp 的 命名空间规范(namespacing etiquette) 更易落地使用。由于所有符号都存储在同一个符号表中(see 创建与编入符号),程序员通常会在每个符号名前加上其所属库的名称作为前缀。例如,函数 text-property-search-forward 和 text-property-search-backward 都隶属于 text-property-search.el 库(see 加载)。通过为符号名添加规范的前缀,能够有效避免不同库中名称相似但功能不同的符号产生命名冲突。然而这种做法往往会导致符号名变得非常长,时间一长,输入和阅读都会十分不便。简写符号则以一种简洁优雅的方式解决了这些问题。
该变量的值是一个关联列表(alist),其元素格式为 (shorthand-prefix . longhand-prefix)。列表中的每个元素都会指示 Lisp 读取器:将所有以 shorthand-prefix 开头的符号形式,视作以 longhand-prefix 开头的符号形式来解析。
该变量仅允许在文件局部变量中设置(see Local Variables in Files in The GNU Emacs Manual)。
下面是一个在假想的字符串操作库 some-nice-string-utils.el 中使用简写符号的示例。
(defun some-nice-string-utils-split (separator s &optional omit-nulls) "A match-data saving variant of `split-string'." (save-match-data (split-string s separator omit-nulls))) (defun some-nice-string-utils-lines (s) "Split string S at newline characters into a list of strings." (some-nice-string-utils-split "\\(\r\n\\|[\n\r]\\)" s))
可以看到,由于需要输入的符号名太长,编写和阅读这段代码都会相当繁琐。我们可以使用简写符号来缓解这一问题。
(defun snu-split (separator s &optional omit-nulls)
"A match-data saving variation on `split-string'."
(save-match-data (split-string s separator omit-nulls)))
(defun snu-lines (s)
"Split string S into a list of strings on newline characters."
(snu-split "\\(\r\n\\|[\n\r]\\)" s))
;; Local Variables:
;; read-symbol-shorthands: (("snu-" . "some-nice-string-utils-"))
;; End:
尽管这两段代码片段看起来不同,但经过 Lisp 读取器处理后,二者会变得完全一致。两种写法最终都会将完全相同的符号注册到符号表中(see 创建与编入符号)。因此,加载或字节编译这两个文件中的任意一个,得到的结果都是等效的。
第二个版本中使用的简写符号 snu-split 和 snu-lines,并不会被注册到符号表中。要验证这一点很简单:将光标移到使用这些简写符号的位置,稍作等待,ElDoc 功能(see Local Variables in Files in The GNU Emacs Manual)就会在回显区提示光标所在位置符号的真实完整名称。
由于 read-symbol-shorthands 是文件局部变量,因此多个依赖some-nice-string-utils-lines.el 库的代码,可能会用不同的简写前缀引用同一个符号,甚至完全不使用简写符号。在下一个示例中,my-tricks.el 库就使用 sns- 前缀(而非 snu-)来引用some-nice-string-utils-lines 这个符号。
(defun t-reverse-lines (s) (string-join (reverse (sns-lines s)) "\n")
;; Local Variables:
;; read-symbol-shorthands: (("t-" . "my-tricks-")
;; ("sns-" . "some-nice-string-utils-"))
;; End:
注意:如果在同一个文件中有两个简写符号,且其中一个是另一个的前缀,那么更长的简写前缀会优先匹配。无论你在文件的局部变量段中以何种顺序定义这些简写,都会按此规则执行。
'(
t//foo ; reads to 'my-tricks--foo', not 'my-tricks-/foo'
t/foo ; reads to 'my-tricks-foo'
)
;; Local Variables:
;; read-symbol-shorthands: (("t/" . "my-tricks-")
;; ("t//" . "my-tricks--")
;; End:
简写符号转换规则存在两种例外情形:
- 或 /= 用作简写前缀,但这不会覆盖掉同名的算术 函数(functions)。
带位置信息的符号(symbol with position) 由一个被称为 原始符号(bare symbol) 的符号,加上一个非负的定长整数( 称为 位置(position))组成。 尽管带位置信息的符号在多数行为上与原始符号一致,但它本身并不是符号:它是一种同时包含原始符号和位置信息的对象。因为带位置信息的符号并非真正的符号,所以它们不在符号表(obarray)中登记,不过它们对应的原始符号通常会登记(see 创建与编入符号)。
字节编译器会使用带位置信息的符号,在其中记录每个符号出现的位置,并在警告和错误信息中使用这些位置。正常情况下不应该在其他场景使用它们,否则在使用 eq、equal 等 Emacs 基础函数时可能会产生意料之外的结果。
带位置信息的符号的打印形式采用 打印表示与读入语法 中描述的井号标记格式,形如 ‘#<symbol foo at 12345>’。它没有对应的读取语法。如果你希望在打印时只输出原始符号,可以在打印操作周围将变量 print-symbols-bare 绑定为非 nil。字节编译器在将输出写入编译后的 Lisp 文件之前会执行这一操作。
当标志变量 symbols-with-pos-enabled 的值为非 nil 时,带位置信息的符号在常规情况下的行为等同于其原始符号。例如,表达式 ‘(eq (position-symbol 'foo 12345) 'foo)’ 的返回值为 t,而 equal 函数也会将带位置信息的符号视作其原始符号来处理。
当 symbols-with-pos-enabled 的值为 nil 时,带位置信息的符号会以自身的身份(而非符号身份)表现行为。例如,表达式 ‘(eq (position-symbol 'foo 12345) 'foo)’ 的返回值为 nil,equal 函数也会判定带位置信息的符号与其原始符号不相等。
在 Emacs 中,绝大多数情况下 symbols-with-pos-enabled 的值都是 nil;但字节编译器和原生编译器在运行时会将其绑定为 t,这种情况下 Emacs 的运行速度会略微变慢。
通常,带位置信息的符号是由字节编译器调用读取器函数 read-positioning-symbols 创建的(see 输入函数)。也可以通过函数 position-symbol 来创建带位置信息的符号。
该变量会影响带位置信息的符号在非打印状态下、且并非本节后续定义函数的参数时的行为。当该变量值为非 nil 时,此类带位置信息的符号表现得与其原始符号一致;否则,它会以自身的身份(而非符号身份)表现行为。
当该变量被绑定为非 nil 时,Lisp 打印器仅打印带位置信息的符号的原始符号,忽略其位置信息。反之,带位置信息的符号会按自身形式打印,而非以符号形式打印。
若 object 是带位置信息的符号,该函数返回 t,否则返回 nil。与 symbolp 不同,该函数不受 symbols-with-pos-enabled 变量的影响。
该函数返回带位置信息的符号 sym 对应的原始符号;若 sym 本身已是普通符号,则直接返回其自身。如果传入的是其他类型的对象,该函数会触发错误。此函数不受 symbols-with-pos-enabled 变量的影响。
该函数从带位置信息的符号 sympos 中提取位置信息(一个非负的定长整数)并返回。如果传入的是其他类型的对象,该函数会触发错误。此函数不受 symbols-with-pos-enabled 变量的影响。
创建一个新的带位置信息的符号。新对象的原始符号取自 sym: 若 sym 是普通符号,则直接使用该符号; 若 sym 是带位置信息的符号,则使用其对应的原始符号。
新对象的位置信息取自 pos: 若 pos 是一个非负的定长整数,则直接使用该数值; 若 pos 是带位置信息的符号,则使用其对应的位置信息。
如果任一参数无效,Emacs 会触发错误。此函数不受 symbols-with-pos-enabled 变量的影响。
在 Emacs Lisp 中,表达式的 求值(evaluation) 由 Lisp 解释器(Lisp interpreter) 完成 —— 这是一个以 Lisp 对象为输入、并计算其作为 表达式的值(value as an expression) 的程序。具体如何求值取决于该对象的数据类型,相关规则将在本章详细说明。解释器会自动运行,以对程序的各个部分进行求值;同时也可以通过 Lisp 原语函数 eval 显式调用。
Lisp 解释器(或称求值器)是 Emacs 中负责计算给定表达式的值的部分。当调用一个用 Lisp 编写的函数时,求值器会通过对函数体中的表达式依次求值,来计算该函数的返回值。因此,运行任何 Lisp 程序,本质上都是在运行 Lisp 解释器。
用于求值的 Lisp 对象被称为 形式(form) 或 表达式(expression) 8。形式是数据对象而非单纯的文本,这是类 Lisp 语言与常规编程语言的核心区别之一。任何对象都可被求值,但实际应用中,数字、符号、列表和字符串是最常被求值的类型。
在后续章节中,我们将详细说明对各类形式进行求值的具体含义。
读取一个 Lisp 形式并对其求值是极为常见的操作,但读取与求值是相互独立的行为,二者均可单独执行。读取操作本身不会对任何内容进行求值;它仅将 Lisp 对象的打印表示形式转换为对象本身。至于该对象是待求值的形式,还是承担完全不同的用途,则由 read 函数的调用者决定。See 输入函数。
求值是一个递归过程,对一个形式求值通常需要先对该形式内部的各个部分求值。例如,当你对一个 函数调用(function call) 形式(如 (car x))求值时,Emacs 会先对参数(子形式 x)求值。参数求值完成后,Emacs 会执行该函数(car);如果该函数是用 Lisp 编写的,执行过程就是对 函数体(body of the function) 进行求值(不过在本例中,car 并非 Lisp 函数,而是用 C 语言实现的原语函数)。See 函数,了解更多关于函数与函数调用的内容。
求值在一个被称为 环境(environment) 的上下文中进行,环境由所有 Lisp 变量的当前值和绑定构成(see 变量)。9 当一个形式引用某个变量但并未为其创建新绑定时,该变量会求值为当前环境所给出的值。对一个形式求值也可能通过绑定变量来临时改变环境(see 局部变量)。
对一个形式进行求值,还可能产生会持续存在的修改,这类修改称为 副作用(side effect)。产生副作用的一个典型例子是形式 (setq foo 1)。
不要把求值与按键解释混为一谈。编辑器的命令循环通过当前激活的键映射,将键盘输入转换为一条命令(一个可交互调用的函数),然后使用 call-interactively 执行该命令。如果该命令是用 Lisp 编写的,执行命令时通常会涉及求值;但这一步不属于按键解释的范畴。See 命令循环。
用于被求值的 Lisp 对象称为 形式(form),或称 表达式(expression)。Emacs 如何对一个形式求值,取决于它的数据类型。Emacs 有三种不同的形式,求值方式各不相同:符号、列表,以及所有其他类型。本节将逐一介绍这三类形式,首先介绍属于自求值形式的其他类型。
自求值形式(self-evaluating form) 是指非列表、非符号的任意形式。自求值形式求值结果就是它自身:求值后的对象与原对象完全相同。因此,数字 25 求值结果为 25,字符串 "foo" 求值结果仍为字符串 "foo"。同样,对向量求值时,并不会对向量内部的元素进行求值 —— 而是直接返回内容不变的原向量。
'123 ; A number, shown without evaluation.
⇒ 123
123 ; Evaluated as usual—result is the same.
⇒ 123
(eval '123) ; Evaluated "by hand"—result is the same.
⇒ 123
(eval (eval '123)) ; Evaluating twice changes nothing.
⇒ 123
自求值形式产生的值会成为程序的一部分,你不应该尝试通过 setcar、aset 或类似操作去修改它。Lisp 解释器可能会对程序中自求值形式产生的常量进行统一化处理,使得这些常量共享结构。See 可变性。
在 Lisp 代码中编写数字、字符、字符串甚至向量是很常见的做法,这正是利用了它们自求值的特性。不过,对于没有读取语法的类型,很少会这样直接书写,因为无法用文本形式表示它们。但可以通过 Lisp 程序构造出包含这些类型的 Lisp 表达式,示例如下:
;; Build an expression containing a buffer object.
(setq print-exp (list 'print (current-buffer)))
⇒ (print #<buffer eval.texi>)
;; Evaluate it.
(eval print-exp)
⊣ #<buffer eval.texi>
⇒ #<buffer eval.texi>
对符号求值时,它会被当作一个变量。如果该符号有值,结果就是这个变量的值;如果该符号作为变量没有值,Lisp 解释器就会报错。关于变量使用的更多信息,参见 变量。
在下面的例子中,我们用 setq 为一个符号赋值。然后对该符号求值,就会得到 setq 所存储的值。
(setq a 123)
⇒ 123
(eval 'a)
⇒ 123
a
⇒ 123
符号 nil 和 t 会被特殊对待:nil 的值永远是 nil,t 的值永远是 t;你不能对它们赋值或绑定为其他值。因此,这两个符号的行为类似于自求值形式,尽管 eval 把它们当作普通符号处理。名称以 ‘:’ 开头的符号同样会自求值;通常它们的值也不能被修改。See 永不改变的变量。
非空列表形式根据其第一个元素,可以是函数调用、宏调用或特殊形式。这三类形式的求值方式各不相同,下文会分别说明。列表中其余的元素构成该函数、宏或特殊形式的 实参(arguments)。
对非空列表进行求值的第一步,是检查它的第一个元素。仅由这个元素就能决定该列表属于哪类形式,以及列表的其余部分该如何处理。第一个元素 不会 被求值,这一点与 Scheme 等其他一些 Lisp 方言不同。
如果列表的第一个元素是一个符号,那么在求值时会检查该符号的函数单元格,并使用其中的内容替代原来的符号。如果该内容仍然是另一个符号,这个被称为 符号函数间接引用(symbol function indirection) 的过程会被重复执行,直到得到一个非符号对象为止。See 函数命名,了解更多关于符号函数间接引用的信息。 我们最终会得到一个非符号对象,它应当是一个函数或其他合适的对象。
更精确地说,此时我们应该得到以下对象之一:Lisp 函数(lambda 表达式)、字节码函数、原语函数、Lisp 宏、特殊形式,或是自动加载对象。这些类型将在后续章节中分别介绍。如果该对象不属于上述任何一种类型,Emacs 将会抛出一个 invalid-function(无效函数)错误。
下面的例子演示了符号间接引用的过程。我们使用 fset 来设置符号的函数单元格,并用 symbol-function 获取函数单元格的内容(see 访问函数单元内容)。具体来说:我们将符号 car 存入符号 first 的函数单元格,再将符号 first 存入符号 erste 的函数单元格。
;; Build this function cell linkage:
;; ------------- ----- ------- -------
;; | #<subr car> | <-- | car | <-- | first | <-- | erste |
;; ------------- ----- ------- -------
(symbol-function 'car)
⇒ #<subr car>
(fset 'first 'car)
⇒ car
(fset 'erste 'first)
⇒ first
(erste '(1 2 3)) ; Call the function referenced by erste.
⇒ 1
与之相反,下面这个示例在调用函数时不会发生任何符号函数间接引用,因为列表的第一个元素是一个匿名 Lisp 函数,而不是符号。
((lambda (arg) (erste arg))
'(1 2 3))
⇒ 1
执行函数本身会对其函数体进行求值;在调用 erste 时,这一过程仍然会触发符号函数间接引用。
这种写法很少使用,现已被废弃。你应当改用下面的写法:
(funcall (lambda (arg) (erste arg))
'(1 2 3))
or just
(let ((arg '(1 2 3))) (erste arg))
内置函数 indirect-function 提供了一种便捷的方式,可显式地执行符号函数间接引用操作。
该函数返回 function 作为函数的实际指向(语义)。若 function 是一个符号,则函数会先查找该符号的函数定义,并以该定义值为起点重新执行上述查找过程;若 function 不是符号,则直接返回 function 本身。
如果最终查找的符号未绑定函数(unbound),该函数会返回 nil。
该函数还有第二个可选参数,但此参数已被废弃(obsolete),且无任何实际作用。
以下是如何用 Lisp 语言自定义实现 indirect-function 的示例:
(defun indirect-function (function)
(if (and function
(symbolp function))
(indirect-function (symbol-function function))
function))
如果正在被求值的列表的第一个元素是 Lisp 函数对象、字节码对象或原语函数对象,那么该列表就是一个 函数调用(function call)。例如,下面是对函数 + 的一次调用:
(+ 1 x)
对函数调用进行求值的第一步,是从左到右依次对列表中除第一个元素外的其余部分进行求值。得到的结果就是实际参数值,列表中的每个元素对应一个值。
下一步是使用这组参数列表去调用该函数,其效果等价于使用函数 apply(see 调用函数)。如果该函数是用 Lisp 编写的,这些实参会用来绑定函数的形参变量(see Lambda 表达式);随后函数体中的各个表达式会按顺序求值,最后一个表达式的值就是本次函数调用的返回值。
如果正在被求值的列表的第一个元素是宏对象,那么该列表就是一个 宏调用(macro call)。对宏调用进行求值时,列表中其余元素一开始并 不会 被求值。相反,这些元素本身会直接作为宏的参数使用。宏的定义会计算出一个替换形式,称为该宏的 展开(expansion) 式,用来替代原来的形式并进行求值。展开式可以是任意形式:自求值常量、符号或列表。如果展开式本身又是一个宏调用,这个展开过程会重复进行,直到得到其他类型的形式为止。
宏调用的常规求值,最终就是对展开式进行求值。不过,宏展开式不一定会被立即求值,甚至可能完全不求值 —— 因为其他程序也会对宏调用进行展开,它们可能会对展开式求值,也可能不会。
通常情况下,参数表达式不会在计算宏展开的过程中被求值,而是作为展开式的一部分出现,等到展开式被求值时才会被计算。
例如,给定如下定义的一个宏:
(defmacro cadr (x) (list 'car (list 'cdr x)))
像 (cadr (assq 'handler list)) 这样的表达式就是一个宏调用,它的展开式为:
(car (cdr (assq 'handler list)))
注意参数 (assq 'handler list) 会出现在展开式中。
关于 Emacs Lisp 宏的完整说明,See 宏。
特殊形式(special form) 是一种被特别标记的原语,使其参数不会被全部求值。大多数特殊形式用于定义控制结构或执行变量绑定 —— 这些都是普通函数无法完成的功能。
每种特殊形式都有自己的规则,规定哪些参数需要求值、哪些参数直接使用而不求值。某个参数是否会被求值,可能取决于其他参数的求值结果。
如果一个表达式的第一个符号是某种特殊形式,该表达式必须遵循该特殊形式的语法规则;否则,Emacs 的行为是未定义的(尽管程序不会崩溃)。例如,((lambda (x) x . 3) 4) 包含一个以 lambda 开头、但格式不合法的子表达式,因此 Emacs 可能会报错,也可能返回 3、4、nil,或出现其他不确定行为。
该谓词函数用于检查其参数是否为特殊形式:若是,则返回 t;否则返回 nil。
以下是 Emacs Lisp 中所有特殊形式的列表(按字母顺序排列),并附带各特殊形式的说明文档引用位置。
andsee 条件组合结构
catchcondsee 条件判断
condition-casesee 编写处理错误的代码
defconstsee 定义全局变量
defvarsee 定义全局变量
functionsee 匿名函数
ifsee 条件判断
interactivesee 交互式调用
lambdasee Lambda 表达式
letlet*see 局部变量
orsee 条件组合结构
prog1prog2prognsee 顺序执行
quotesee 引用
save-current-buffersave-excursionsee Excursions
save-restrictionsee Narrowing
setqsee 修改变量值
setq-defaultsee 创建与删除缓冲区局部绑定
unwind-protectsee 非局部退出
whilesee 迭代
Common Lisp 注: 下面是 GNU Emacs Lisp 与 Common Lisp 中特殊形式的一些对比。
setq、if和catch在 Emacs Lisp 与 Common Lisp 中都是特殊形式。save-excursion是 Emacs Lisp 中的特殊形式,但 Common Lisp 中不存在。throw在 Common Lisp 中是特殊形式(因为它必须能抛出多个值),但在 Emacs Lisp 中是函数(后者不支持多值)。
特殊形式 quote 会原样返回它唯一的参数,不对其进行求值。这提供了一种在程序中使用常量符号和列表的方式(符号与列表本身并非自求值对象)。(数字、字符串、向量这类自求值对象不需要加 quote。)
由于 quote 在程序中使用频率极高,Lisp 为此提供了一种便捷的读取语法。一个撇号字符(‘'’)后跟一个 Lisp 对象(采用读取语法格式),会展开为一个列表:该列表的第一个元素是 quote,第二个元素则是这个对象。因此,读取语法 'x 是 (quote x) 的简写形式。
以下是一些使用 quote 的表达式示例:
(quote (+ 1 2))
⇒ (+ 1 2)
(quote foo)
⇒ foo
'foo
⇒ foo
''foo
⇒ 'foo
'(quote foo)
⇒ 'foo
['foo]
⇒ ['foo]
尽管表达式 (list '+ 1 2) 和 '(+ 1 2) 都会生成与 (+ 1 2) 相等的列表,但前者生成的是全新创建的可变列表,而后者生成的列表由可能被共享的 cons 单元构成,不应被修改。
See 自求值形式。
其他引用类构造包括 function(see 匿名函数)—— 它会对以 Lisp 编写的匿名 lambda 表达式进行编译;以及 ‘`’(see 反引号)—— 该符号用于仅引用列表的部分内容,同时计算并替换列表的其他部分。
反引号构造(Backquote constructs) 允许你对一个列表进行引用,同时有选择地对列表中的部分元素求值。在最简单的情况下,它和特殊形式
quote
的作用完全相同(上一节已介绍;see 引用。
例如,下面这两种形式会产生完全相同的结果:
`(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
'(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
反引号参数内部的特殊标记 ‘,’ 用来表示非常量的值。Emacs Lisp 求值器会对 ‘,’ 后面的表达式进行求值,并将结果放入列表结构中。
`(a list of ,(+ 2 3) elements)
⇒ (a list of 5 elements)
使用 ‘,’ 进行替换,在列表结构更深层的嵌套中同样允许。例如:
`(1 2 (3 ,(+ 4 5)))
⇒ (1 2 (3 9))
你也可以使用特殊标记 ‘,@’,将一个已求值的结果 拼接(splice) 到最终生成的列表中。被拼接列表的元素会成为最终列表中与其他元素同一层级的元素。如果不使用 ‘`’,实现同等功能的代码往往难以阅读。以下是一些示例:
(setq some-list '(2 3))
⇒ (2 3)
(cons 1 (append some-list '(4) some-list))
⇒ (1 2 3 4 2 3)
`(1 ,@some-list 4 ,@some-list)
⇒ (1 2 3 4 2 3)
(setq list '(hack foo bar))
⇒ (hack foo bar)
(cons 'use
(cons 'the
(cons 'words (append (cdr list) '(as elements)))))
⇒ (use the words foo bar as elements)
`(use the words ,@(cdr list) as elements)
⇒ (use the words foo bar as elements)
如果反引号构造中的某个子表达式不包含替换或拼接,它的行为就等价于 quote:生成的 cons 单元、向量和字符串可能会被共享,因此不应该被修改。
See 自求值形式。
通常情况下,表达式会因为出现在运行中的程序里而自动被求值。只有在少数场景下,你才需要编写代码,对运行时才计算出来的表达式进行求值 ——比如从正在编辑的文本中读取一个表达式,或是从属性列表中获取一个表达式。这时就可以使用 eval 函数。
很多时候其实并不需要使用 eval,应该改用其他方式:例如,要获取变量的值,虽然 eval 也能用,但更推荐用 symbol-value;与其把表达式存在属性列表里,之后再用 eval 求值,不如直接存储函数,再通过 funcall 调用。
本节介绍的函数和变量,可用于对表达式求值、为求值过程设定限制,或记录最近的返回值。加载文件本身也会执行求值(see 加载)。
通常来说,更清晰、更灵活的做法是:把函数存放到数据结构中,再用 funcall 或 apply 调用,而不是把表达式存进去再用 eval 求值。使用函数可以方便地以参数形式向其传递信息。
这是用于对表达式进行求值的基础函数。它会在当前环境中对 form 进行求值,并返回求值结果。form 对象的类型决定了它的求值方式。See 形式的种类。
参数 lexical 用于指定局部变量的作用域规则(see Scoping 变量绑定的作用域规则):
若值为 t,表示使用词法作用域对 form 求值(这是推荐使用的值);
若省略该参数或值为 nil,则使用旧的「仅动态作用域」规则。
lexical 的值也可以是一个非空列表,用于为词法绑定指定特定的 词法环境(lexical environment);不过该特性仅适用于特殊场景(例如 Emacs Lisp 调试器)。列表中的每个成员要么是一个表示「词法符号 - 值对」的 cons 单元,要么是一个符号(代表某个特殊变量,该变量若被绑定则会使用动态作用域)。
由于 eval 本身是一个函数,因此调用 eval 时传入的参数表达式会被求值两次:第一次是在调用 eval 之前的参数准备阶段,第二次则是 eval 函数自身对该表达式的求值。示例如下:
(setq foo 'bar)
⇒ bar
(setq bar 'baz)
⇒ baz
;; Here eval receives argument foo
(eval 'foo)
⇒ bar
;; Here eval receives argument bar, which is the value of foo
(eval foo)
⇒ baz
当前对 eval 的活跃调用层数被限制为 max-lisp-eval-depth(见下文)。
该函数会对当前缓冲区中,由位置 start 和 end 界定的区域内的表达式进行求值。它会从该区域中读取表达式,并逐个调用 eval 对其求值,直至到达区域末尾,或触发未被处理的错误为止。
默认情况下,eval-region 不会产生任何输出。但如果 stream 参数的值非 nil,那么输出函数(see 输出函数)产生的所有输出,以及对该区域内表达式求值得到的结果,都会通过 stream 进行打印。See 输出流。
若 read-function 参数的值非 nil,则它必须是一个函数 ——该函数会替代 read,用于逐个读取表达式。调用此函数时会传入一个参数(即用于读取输入的流)。你也可以通过变量 load-read-function(see 程序的加载方式)来指定这个读取函数,但使用 read-function 参数的方式更健壮。
eval-region 不会移动光标位置(point),该函数始终返回 nil。
该函数与 eval-region 功能类似,但参数提供了不同的可选特性。eval-buffer 会对缓冲区 buffer-or-name 的整个可访问区域进行操作(see Narrowing in The GNU Emacs Manual)。buffer-or-name 可以是一个缓冲区对象、缓冲区名称(字符串类型),也可以是 nil(或省略该参数)—— 这种情况下会使用当前缓冲区。
stream 参数的用法与 eval-region 中一致,除非 stream 为 nil 且 print 非 nil:此时,表达式求值产生的结果仍会被丢弃,但输出函数的输出内容会打印在回显区中。
filename 是用于 load-history 的文件名(see 卸载),默认值为 buffer-file-name(see Buffer File Name)。若 unibyte 非 nil,则 read 函数会尽可能将字符串转换为单字节编码。
该变量用于定义对 eval、apply 和 funcall 的调用所允许的最大嵌套深度,超出则会抛出错误(错误信息为 "Lisp nesting exceeds max-lisp-eval-depth")。
设置这一限制并在超限时抛出错误,是 Emacs Lisp 用于避免因函数定义不当而导致无限递归的机制。如果把 max-lisp-eval-depth 的值调得过大,这类代码反而可能引发栈溢出。在部分系统上,这种溢出可以被处理:此时正常的 Lisp 求值会被中断,控制流返回到顶层命令循环(top-level)。注意:这种情况下无法进入 Emacs Lisp 调试器。See 发生错误时进入调试器。
深度计数包含 eval、apply、funcall 的内部使用(例如调用 Lisp 表达式中提到的函数、递归求值函数参数与函数体),也包含 Lisp 代码中显式的直接调用。
该变量的默认值为 1600。如果将其设为小于 100 的值,当达到该值时 Lisp 会自动将其重置为 100。
为了能够调试无限递归错误,在进入 Lisp 调试器时,如果剩余深度空间很小,Emacs 会临时增大 max-lisp-eval-depth 的值,以确保调试器自身有足够的空间运行。在运行 handler-bind 的异常处理器时也会执行同样的操作。See 编写处理错误的代码。
变量 lisp-eval-depth-reserve 限制了 Emacs 在这些特殊场景下,可以给 max-lisp-eval-depth 额外增加的深度上限。
该变量的默认值为 200。
该变量的值是一个列表,保存了由 Emacs 标准命令从缓冲区(包括小缓冲区)中读取、求值并打印的所有表达式的返回值。(注意:这 不包括 在 *ielm* 缓冲区中的求值,也不包括在 lisp-interaction-mode 下使用 C-j、C-x C-e 等类似求值命令的求值结果。)
该变量已被废弃,会在未来版本中移除,因为它会持续增大 Emacs 进程的内存占用。因此我们不建议使用它。
values 中的元素按最新返回的在前排列。
(setq x 1)
⇒ 1
(list 'A (1+ 2) auto-save-default)
⇒ (A 3 t)
values
⇒ ((A 3 t) 1 ...)
这个变量可用于回溯最近求值过的表达式的结果。
通常不建议直接打印 values 本身,因为它可能非常长。你应该像下面这样,只查看其中特定的元素:
;; Refer to the most recent evaluation result.
(nth 0 values)
⇒ (A 3 t)
;; That put a new element on, ;; so all elements move back one. (nth 1 values) ⇒ (A 3 t)
;; This gets the element that was next-to-most-recent ;; before this example. (nth 3 values) ⇒ 1
有时候,推迟表达式的求值是很有用的。例如:如果后续程序中可能根本用不到某个结果,你就可以避免执行一次耗时的计算。 thunk 库提供了下面这些函数和宏,来支持这种 延迟求值(deferred evaluation):
返回一个用于对 forms 进行求值的 惰性计算对象(thunk)。thunk 是一个闭包(see 闭包),它会继承 thunk-delay 调用处的词法环境。使用该宏需要开启 lexical-binding(词法绑定)。
强制执行 thunk,对创建该 thunk 的 thunk-delay 中指定的表达式进行求值。函数会返回最后一个表达式的求值结果。该 thunk 还会 “记住(remembers)”自己已被执行:后续对同一个 thunk 调用 thunk-force 时,只会直接返回相同结果,而不会再次求值这些表达式。
该宏与 let 类似,但会创建 “惰性(lazy)” 变量绑定。每个绑定的形式为 (symbol value-form)。与 let 不同的是:value-form 的求值会被推迟,直到在对 forms 求值时,第一次使用对应符号 symbol 的绑定才会触发求值。每个 value-form 最多只会被求值一次。使用该宏需要开启 lexical-binding。
示例:
(defun f (number)
(thunk-let ((derived-number
(progn (message "Calculating 1 plus 2 times %d" number)
(1+ (* 2 number)))))
(if (> number 10)
derived-number
number)))
(f 5) ⇒ 5
(f 12) ⊣ Calculating 1 plus 2 times 12 ⇒ 25
由于惰性绑定变量的特殊性质,对它们进行赋值(例如使用 setq)会报错。
该宏与 thunk-let 类似,但允许 bindings 中的表达式引用当前 thunk-let* 中前面已经定义的绑定。使用该宏需要开启 lexical-binding。
(thunk-let* ((x (prog2 (message "Calculating x...")
(+ 1 1)
(message "Finished calculating x")))
(y (prog2 (message "Calculating y...")
(+ x 1)
(message "Finished calculating y")))
(z (prog2 (message "Calculating z...")
(+ y 1)
(message "Finished calculating z")))
(a (prog2 (message "Calculating a...")
(+ z 1)
(message "Finished calculating a"))))
(* z x))
⊣ Calculating z...
⊣ Calculating y...
⊣ Calculating x...
⊣ Finished calculating x
⊣ Finished calculating y
⊣ Finished calculating z
⇒ 8
thunk-let 和 thunk-let* 会隐式使用 thunk:它们在展开时会创建辅助符号,并将这些符号绑定到包裹了绑定表达式的 thunk 上。函数体 forms 中对原变量的所有引用,都会被替换成以对应辅助变量为参数调用 thunk-force 的表达式。
因此,任何使用 thunk-let 或 thunk-let* 的代码都可以改写成直接使用 thunk,但在很多场景下,使用这些宏写出的代码比显式使用 thunk 更简洁优雅。
Lisp 程序由一组 表达式(expression) 或称 形式(form) 构成(see 形式的种类)。我们通过将这些形式放入 控制结构(control structures) 中来控制它们的执行顺序。控制结构是一类特殊形式,用于控制其所包含的形式何时执行、是否执行、执行多少次。
最简单的执行顺序是顺序执行:先执行形式 a,再执行形式 b,依此类推。当你在函数体或 Lisp 代码文件的顶层连续写下多个形式时,就会发生这种情况 ——形式会按照书写顺序执行。我们称之为 文本顺序(textual order)。例如,如果一个函数体由 a 和 b 两个形式组成,那么对该函数的求值会先计算 a,再计算 b,而 b 的求值结果将成为该函数的返回值。
显式的控制结构使得实现非顺序的执行顺序成为可能。
以下是这段 Emacs Lisp 文档的精准简体中文翻译,严格遵循技术文档的专业性和可读性: Emacs Lisp 提供了多种类型的控制结构,包括其他形式的顺序执行、条件判断、循环迭代以及(受控的)跳转 — 所有这些都会在下文展开讨论。内置的控制结构属于特殊形式,因为其包含的子形式并非一定会被求值,也不会按顺序求值。你可以使用宏来定义自定义的控制结构语法(see 宏)。
按照形式出现的顺序对其求值,是控制流程从一个形式传递到另一个形式最常用的方式。在某些上下文(例如函数体)中,这一过程会自动发生。在其他场景下,你则必须使用一种控制结构语法来实现这一点:progn—— 这是 Lisp 中最简单的控制结构。
progn 特殊形式的语法如下:
(progn a b c ...)
它的作用是按顺序执行形式 a、b、c 等。这些形式被称为 progn 形式的 主体(body)。主体中最后一个形式的求值结果会成为整个 progn 的返回值。(progn)(无参数调用时)返回 nil。
在 Lisp 发展早期,progn 是唯一能连续执行两个或多个形式、并取用最后一个形式求值结果的方式。但程序员们发现,他们经常需要在函数体中使用 progn—— 因为当时的函数体只允许包含一个形式。因此,函数体被设计为隐式的 progn:就像真正的 progn 主体一样,函数体中可以包含多个形式。许多其他控制结构也同样内置了隐式的 progn。这使得 progn 的使用频率远不如多年前那么高。如今它最常用的场景是在 unwind-protect、and、or 内部,或是 if 的 then 分支中。
该特殊形式会按照文本顺序对所有 forms 依次求值,并返回最后一个形式的求值结果。
(progn (print "The first form")
(print "The second form")
(print "The third form"))
⊣ "The first form"
⊣ "The second form"
⊣ "The third form"
⇒ "The third form"
另外两个结构同样会对一系列形式进行求值,但返回的值不同:
该特殊形式按照文本顺序对 form1 以及所有 forms 依次求值,并返回 form1 的结果。
(prog1 (print "The first form")
(print "The second form")
(print "The third form"))
⊣ "The first form"
⊣ "The second form"
⊣ "The third form"
⇒ "The first form"
有一种方法可以移除变量 x 所指向列表中的第一个元素,并返回这个被移除的元素的值:
(prog1 (car x) (setq x (cdr x)))
该特殊形式会按照文本顺序依次对 form1、form2 以及后续所有 forms 进行求值,并返回 form2 的求值结果。
(prog2 (print "The first form")
(print "The second form")
(print "The third form"))
⊣ "The first form"
⊣ "The second form"
⊣ "The third form"
⇒ "The second form"
条件控制结构用于在多个备选逻辑中做出选择。Emacs Lisp 提供五种条件形式:if(其用法与其他编程语言基本一致)、when 和 unless(均为 if 的变体)、cond(通用化的分支语句)以及 pcase(cond 的进一步通用化形式,see 模式匹配条件)。
if 会根据 condition(条件)的求值结果,在 then-form(then 分支形式)和 else-forms(else 分支形式)之间选择执行逻辑:若 condition 求值结果为非 nil,则执行 then-form 并返回其结果;否则按文本顺序执行所有 else-forms,并返回最后一个形式的求值结果。(if 的 else 部分是隐式 progn 的典型示例。See 顺序执行。)
若 condition 的求值结果为 nil,且未指定任何 else-forms,则 if 返回 nil。
if 属于特殊形式,原因在于未被选中的分支永远不会被求值 —— 会被直接忽略。因此在以下示例中,true 不会被打印出来,因为 print 函数根本不会被调用:
(if nil
(print 'true)
'very-false)
⇒ very-false
这是 if 的一个变体形式,它不含 else-forms(else 分支形式),且可以包含多个 then-forms(then 分支形式)。具体来说,
(when condition a b c)
完全等价于
(if condition (progn a b c) nil)
这是 if 的一个变体形式,它不含 then-form(then 分支形式):
(unless condition a b c)
完全等价于
(if condition nil a b c)
cond 可在任意数量的备选逻辑中做选择。cond 中的每个 clause(分支子句)都必须是一个列表:该列表的 CAR(首部元素)为 condition(条件);若列表还有剩余元素,则这些元素为 body-forms(主体形式)。因此,一个分支子句的结构如下:
(condition body-forms...)
cond 会按照文本顺序依次尝试各个分支子句:先对每个子句的 condition(条件)进行求值。若 condition 的求值结果为非 nil,则该子句判定为「成功」;此时 cond 会执行该子句的 body-forms(主体形式),并返回最后一个 body-forms 的求值结果。后续所有剩余子句都会被忽略。
若 condition 的求值结果为 nil,则该子句判定为「失败」,cond 会继续处理下一个子句,对其 condition 进行求值判断。
分支子句也可以采用如下形式:
(condition)
此时,若检测到 condition(条件)的求值结果为非 nil,则该 cond 形式会返回 condition 的值。
若所有 condition 的求值结果均为 nil(即所有分支子句都判定为失败),则 cond 返回 nil。
以下示例包含四个分支子句,分别用于检测 x 的值是否为数字、字符串、缓冲区和符号:
(cond ((numberp x) x)
((stringp x) x)
((bufferp x)
(setq temporary-hack x) ; multiple body-forms
(buffer-name x)) ; in one clause
((symbolp x) (symbol-value x)))
我们经常需要在前面所有分支都不匹配时,执行最后一个分支。为此,我们可以把 t 用作最后一个分支的 condition(条件),形如:(t body-forms)。形式 t 的求值结果是 t,它永远不会是 nil,因此只要 cond 执行到这个分支,它就一定会成功。例如:
(setq a 5)
(cond ((eq a 'hack) 'foo)
(t "default"))
⇒ "default"
这个 cond 表达式在 a 的值为 hack 时返回 foo,否则返回字符串 "default"。
所有条件结构都可以用 cond 或 if 来表示。因此,二者之间的选择只是风格问题。例如:
(if a b c) ≡ (cond (a b) (t c))
在使用条件判断的同时绑定变量往往会很方便。常见的场景是:你先计算出一个值,然后在该值非 nil 时对它做一些处理。直接的写法可以像下面这样,例如:
(let ((result1 (do-computation)))
(when result1
(let ((result2 (do-more result1)))
(when result2
(do-something result2)))))
由于这是一种非常常见的模式,Emacs 提供了许多宏来让这一写法更简便、更易读。上面的代码也可以改用下面这种方式来写:
(when-let* ((result1 (do-computation))
(result2 (do-more result1)))
(do-something result2))
围绕这种模式有许多变体,下面会对它们做简要说明。
依次对 varlist 中的每个绑定进行求值,若某个绑定的值为 nil 则停止。如果所有绑定的值都非 nil,则返回 then-form 的值;否则返回 else-forms 中最后一个形式的值。
varlist 中的每个元素都具有格式 (symbol value-form):对 value-form 求值,并将 symbol 局部绑定到该结果。绑定是顺序进行的,与 let* 类似(see 局部变量)。作为一种特殊情况:如果只关心 value-form 的判断结果,可以省略 symbol:此时会对 value-form 求值并检查是否为 nil,但不会绑定它的值。
依次对 varlist 中的每个绑定求值,若某个绑定的值为 nil 则停止。如果所有绑定都非 nil,则返回 then-forms 中最后一个形式的值。
varlist 的格式与 if-let* 相同:varlist 中的每个元素格式为 (symbol value-form),其中对 value-form 求值,并将 symbol 局部绑定到该结果。绑定按顺序进行,与 let* 一致(see 局部变量)。作为一种特殊情况:如果只关心 value-form 的判断结果,可以省略 symbol:此时会对 value-form 求值并检查是否为 nil,但不会绑定其值。
依次对 varlist 中的每个绑定求值,若某个绑定的值为 nil 则停止。如果所有绑定都非 nil,则返回 then-forms 中最后一个形式的值;如果没有 then-forms,则返回最后一个绑定的值。
varlist 的格式与 if-let* 相同:varlist 中的每个元素格式为 (symbol value-form),其中对 value-form 求值,并将 symbol 局部绑定到该结果。绑定按顺序进行,与 let* 一致(see 局部变量)。作为一种特殊情况:如果只关心 value-form 的判断结果,可以省略 symbol:此时会对 value-form 求值并检查是否为 nil,但不会绑定其值。
部分 Lisp 程序员遵循这样的惯例:and 和 and-let* 用于关注返回值的形式求值,而 when 和 when-let* 用于关注副作用、忽略返回值的形式求值。
Emacs 还提供了类似的宏,用于循环执行直到某个绑定求值为 nil:
依次对 spec 中的每个绑定求值,若某个绑定的值为 nil 则停止。如果所有绑定都非 nil,则执行 then-forms,然后重复循环。注意:循环重复时,spec 中的 value-form 会被重新求值,绑定也会重新建立。
varlist 的格式与 if-let* 相同:varlist 中的每个元素格式为 (symbol value-form),其中对 value-form 求值,并将 symbol 局部绑定到该结果。绑定按顺序进行,与 let* 一致(see 局部变量)。作为一种特殊情况:如果只关心 value-form 的判断结果,可以省略 symbol:此时会对 value-form 求值并检查是否为 nil,但不会绑定其值。
while-let 的返回值永远是 nil。
本节介绍常与 if、cond 配合使用、用于表达复杂条件的结构。and 和 or 本身也可单独作为多条件判断结构使用。
该函数用于判断 condition 是否为假。如果 condition 为 nil,则返回 t;否则返回 nil。函数 not 与 null 完全等价。如果你是在判断空列表或 nil 值,我们推荐使用 null。
and 特殊形式用于判断所有 conditions(条件)是否都为真。它会按照书写顺序逐个对 conditions 进行求值。
若任意一个 conditions 的求值结果为 nil,则无论剩余 conditions 的值如何,and 的结果都必然是 nil;因此 and 会立即返回 nil,并忽略剩余的 conditions。
若所有 conditions 的求值结果均为非 nil,则最后一个条件的值会成为整个 and 形式的返回值。单独的 (and)(无任何 conditions)会返回 t,这是合理的 ——因为所有条件(空集)都满足非 nil 的要求。(不妨思考一下:哪一个条件不满足呢?)
以下是一个示例:第一个条件返回整数 1(非 nil),第二个条件同样返回整数 2(非 nil),第三个条件为 nil,因此后续的条件永远不会被求值。
(and (print 1) (print 2) nil (print 3))
⊣ 1
⊣ 2
⇒ nil
下面是一个更贴近实际使用的 and 示例:
(if (and (consp foo) (eq (car foo) 'x))
(message "foo is a list starting with x"))
注意:若 (consp foo) 返回 nil,则 (car foo) 不会被执行,从而避免产生错误。
and 表达式也可以用 if 或 cond 来改写,写法如下:
(and arg1 arg2 arg3) ≡ (if arg1 (if arg2 arg3)) ≡ (cond (arg1 (cond (arg2 arg3))))
or 是一种特殊形式,用于判断所有 conditions(条件)中至少有一个为真。它会按照书写顺序逐个对所有条件进行求值。
如果任意一个 conditions 求值结果为非 nil,那么 or 的结果必然为非 nil;因此 or 会立即返回,并忽略剩余的条件。返回的值就是刚刚求值成功的那个条件的非 nil 值。
如果所有 conditions 最终都为 nil,则 or 表达式返回 nil。单独的 (or)(不带任何条件)返回 nil,这是合理的 —— 因为所有条件(空集)都为 nil。(不妨想一想:哪一个不是呢?)
例如,下面这个表达式用于判断 x 是 nil 还是整数 0:
(or (eq x nil) (eq x 0))
与 and 结构一样,or 也可以用 cond 来实现。例如:
(or arg1 arg2 arg3)
≡
(cond (arg1)
(arg2)
(arg3))
你几乎可以用 if 来实现 or,但并不完全等价:
(if arg1 arg1
(if arg2 arg2
arg3))
这种写法并非完全等价,因为它可能会对 arg1 或 arg2 进行两次求值。相比之下,(or arg1 arg2 arg3) 绝不会对任何参数求值超过一次。
该函数返回 condition1 和 condition2 的异或(互斥或) 布尔结果。具体来说:如果两个参数同为 nil,或同为非 nil,则 xor 返回 nil;否则,返回那个值为非 nil 的参数本身。
注意:与 or 不同,该函数总会对两个参数都进行求值(无短路特性)。
除了四种基本的条件形式之外,Emacs Lisp 还提供了一种模式匹配条件形式——pcase 宏。它是 cond 与 cl-case 的混合体(see Conditionals in Common Lisp Extensions),克服了二者的局限,并引入了模式匹配编程风格。
pcase 所解决的局限包括:
cond 形式通过对每个分支的 condition(条件)谓词进行求值,来在多个选项中做出选择(see 条件判断)。它的主要局限是:在 condition 中通过 let 绑定的变量,在该分支的 body-forms(主体形式)中不可用。
另一个麻烦点(与其说是局限,不如说是不便之处)是:当一系列 condition 谓词都是做相等性判断时,会出现大量重复代码。(cl-case 解决了这一不便。)
cl-case 宏通过将其第一个参数与一组特定值进行相等性比较,来在多个选项中选择。
它的局限体现在两个方面:
eql 函数。
这些特性导致 cl-case 不适用于字符串或复合数据结构(例如列表或向量)。
(cond 没有这些局限,但它存在其他局限,详见上文。)
从概念上讲,pcase 宏借鉴了 cl-case 以第一个参数为中心的特点,以及 cond 的分支处理流程;它用一种泛化的相等性判断(属于 模式匹配(patern matching) 的一种变体)替代了 condition,并增加了相应机制,让你可以简洁地表达分支的判断条件,同时在分支的判断条件与 body-forms 之间共享 let 绑定。
这种对判断条件的简洁表达形式被称为 模式(pattern)。当作用于第一个参数值的判断条件返回非 nil 时,我们称 “模式与该值匹配(the pattern matches the value)”(有时也说 “该值与模式匹配(the value matches the pattern)”)。
pcase 宏 ¶相关背景知识,See 模式匹配条件。
clauses 中的每个分支格式为:(pattern body-forms…)。
首先对 expression 求值得到其结果 expval;然后在 clauses 中找到第一个 pattern(模式)与 expval 匹配的分支,并将程序控制权转移到该分支的 body-forms(主体形式)。
如果存在匹配的分支,pcase 的返回值为匹配成功的分支中最后一个 body-forms 的求值结果;若没有任何分支匹配,则 pcase 求值结果为 nil。
每个 pattern 必须是一个 pcase 模式,它既可以使用下面定义的核心模式之一,也可以使用通过 pcase-defmacro 定义的模式(see 扩展 pcase)。
本小节的后续部分会介绍不同形式的核心模式,给出一些示例,并对某些模式提供的变量绑定功能给出重要的使用注意事项。核心模式可以是以下几种形式:
_ (underscore)匹配任意 expval。 也被称为 忽略匹配(don’t care)或 通配符(wildcard)。
'val当 expval 等于 val 时匹配。比较方式等价于 equal(see 相等性谓词)。
keywordintegerstring当 expval 等于该字面量对象时匹配。这是上文 'val 模式的一种特殊情况,之所以可行,是因为这类类型的字面量对象是自引用(self-quoting) 的。
symbol匹配任意 expval,同时会将 symbol 局部绑定(let-bind) 到 expval,使得该绑定在 body-forms 中可用(see 动态绑定)。
若 symbol 是序列模式 seqpat 的一部分(例如通过下文的 and 构建),则该绑定在 seqpat 中 symbol 出现位置之后的部分也可用。这种用法存在一些注意事项,详见 注意事项。
有两个符号需要避免使用:t 的行为与上文的 _ 相同(已废弃),nil 会触发错误。同理,绑定关键字符号(see 永不改变的变量)也无实际意义。
`qpat反引号风格的模式。See 反引号风格模式。
(cl-type type)当 expval 的类型为 type 时匹配。type 是 cl-typep 所接受的类型描述符(see Type Predicates in Common Lisp Extensions)。例如:
(cl-type integer) (cl-type (integer 0 10))
(pred function)当谓词 function 作用于 expval 时返回非 nil 值,则匹配成功。可通过 (pred (not function)) 语法对该判断结果取反。
谓词 function 可以是以下形式之一:
以 expval 作为唯一参数调用该命名函数。
示例:integerp
以 expval 作为唯一参数调用该匿名函数(see Lambda 表达式)。
示例:(lambda (n) (= 42 n))
调用该函数(函数调用形式的第一个元素)时,传入 n 个指定参数(函数调用形式的其余元素),并额外增加第 n+1 个参数,其值为 expval。
示例:(= 42)
此示例中,函数为 =,n 的值为 1,实际执行的函数调用为:(= 42 expval)。
_ arg调用该函数(函数调用形式的第一个元素)时,
传入指定的参数(函数调用形式的其余元素),
并将其中的 _ 替换为 expval。
示例:(gethash _ memo-table)此示例中,函数为 gethash,实际执行的函数调用为:(gethash expval memo-table)。
(app function pattern)当 function 作用于 expval 后返回的值能匹配 pattern 时,该模式匹配成功。function 可以采用上文为 pred 模式描述的任意一种形式。但与 pred 不同的是,app 会将函数返回结果与 pattern 进行匹配,而非判断其是否为布尔真值。
(guard boolean-expression)当 boolean-expression(布尔表达式)求值结果为非 nil 时,该模式匹配成功。
(let pattern expr)先对 expr 求值得到 exprval,若 exprval 能匹配 pattern,则该模式匹配成功。
(之所以命名为 let,是因为 pattern 可通过 symbol 形式将符号绑定到对应值。)
序列模式(sequencing pattern),也叫 seqpat,是一种按顺序处理其子模式参数的模式。
pcase 提供了两种序列模式:and 和 or。它们的行为与同名的特殊形式类似(see 条件组合结构),但它们处理的是子模式,而非数据值。
(and pattern1…)按顺序依次尝试匹配 pattern1… 直到其中一个匹配失败。一旦某个子模式不匹配,整个 and 模式就匹配失败,剩余的子模式不再继续测试。如果所有子模式都匹配成功,则 and 模式匹配成功。
(or pattern1 pattern2…)按顺序依次尝试匹配 pattern1、pattern2、…,直到其中一个匹配成功。一旦某个子模式匹配成功,整个 or 模式即匹配成功,剩余的子模式不再继续测试。
为了提供一致的变量环境
To present a consistent environment
(see 求值简介)
给 body-forms (从而避免匹配后出现求值错误),该模式所绑定的变量集合是所有子模式绑定变量的并集。如果某个变量并非由最终匹配成功的那个子模式绑定,则它会被绑定为 nil。
(rx rx-expr…)使用 rx 正则表达式表示法(see The rx Structured Regexp Notation),将字符串与正则表达式 rx-expr… 进行匹配,效果等价于 string-match。
除了常规的 rx 语法之外,rx-expr… 中还可以包含以下结构:
(let ref rx-expr…)将符号 ref 绑定到匹配 rx-expr... 的子匹配结果上。在 body-forms 中,ref 会被绑定为该子匹配对应的字符串(若无匹配则为 nil),同时该符号也可在 backref 中使用。
(backref ref)行为与标准的 backref 结构类似,但此处的 ref 还可以是由前面(let ref …) 结构定义的命名符号。
cl-case 的优势 ¶下面这个示例会突出展示 pcase 相比 cl-case 所具备的一些优势(see Conditionals in Common Lisp Extensions)。
(pcase (get-return-code x) ;; string ((and (pred stringp) msg) (message "%s" msg))
;; symbol
('success (message "Done!"))
('would-block (message "Sorry, can't do it now"))
('read-only (message "The schmilblick is read-only"))
('access-denied (message "You do not have the needed rights"))
;; default (code (message "Unknown return code %S" code)))
使用 cl-case 时,你需要显式声明一个局部变量 code 来存储 get-return-code 的返回值。此外,由于 cl-case 使用 eql 进行比较,它很难用于字符串的匹配场景。
and 模式 ¶一种常见的写法是编写以 and 开头的模式,通过一个或多个 symbol(符号)子模式,为后续的子模式(以及分支体)提供变量绑定。例如,以下模式可匹配一位数的整数。
(and
(pred integerp)
n ; bind n to expval
(guard (<= -9 n 9)))
首先,当 (integerp expval) 求值结果为非 nil 时,pred 模式匹配成功。其次,n 是一个 symbol(符号)模式,它能匹配任意值,并将 n 绑定到 expval。最后,当布尔表达式 (<= -9 n 9) (注意此处对 n 的引用)求值结果为非 nil 时,guard 模式匹配成功。只有当所有这些子模式都匹配成功时,整个 and 模式才会匹配成功。
pcase 重构代码 ¶以下示例展示了如何将一个简单匹配任务的传统实现方式(函数 grok/traditional)重构为使用 pcase 的实现方式(函数 grok/pcase)。这两个函数的文档字符串均为:“如果 OBJ 是形如 "key:NUMBER" 的字符串,则返回 NUMBER(字符串类型);否则,返回列表 ("149" default)。”
首先给出传统实现方式(see Regular Expressions):
(defun grok/traditional (obj)
(if (and (stringp obj)
(string-match "^key:\\([[:digit:]]+\\)$" obj))
(match-string 1 obj)
(list "149" 'default)))
(grok/traditional "key:0") ⇒ "0"
(grok/traditional "key:149") ⇒ "149"
(grok/traditional 'monolith) ⇒ ("149" default)
该重构示例展示了符号绑定,以及 or、and、pred、app 和 let 等模式的用法。
(defun grok/pcase (obj)
(pcase obj
((or ; line 1
(and ; line 2
(pred stringp) ; line 3
(pred (string-match ; line 4
"^key:\\([[:digit:]]+\\)$")) ; line 5
(app (match-string 1) ; line 6
val)) ; line 7
(let val (list "149" 'default))) ; line 8
val))) ; line 9
(grok/pcase "key:0") ⇒ "0"
(grok/pcase "key:149") ⇒ "149"
(grok/pcase 'monolith) ⇒ ("149" default)
grok/pcase 的主体是 pcase 形式里的单个分支:模式部分在第 1–8 行,(唯一的)主体代码在第 9 行。
整个模式是 or,它会依次尝试匹配它的各个子模式:先匹配 and(第 2–7 行),再匹配 let(第 8 行),直到其中一个匹配成功。
与上一个示例(see 示例 1)类似,and 以一个 pred 子模式开头,用于确保后续子模式作用于正确类型的对象(本例中是字符串)。如果 (stringp expval) 返回 nil,则 pred 匹配失败,从而整个 and 也匹配失败。
下一个 pred(第 4–5 行)会求值
(string-match RX expval),
若结果非 nil 则匹配成功,这表示 expval 符合期望的格式:key:NUMBER。同样,一旦此处失败,pred 与整个 and 都会匹配失败。
最后(在这组 and 子模式中),app 会对 (match-string 1 expval)(第 6 行)求值,得到一个临时值 tmp(即 “NUMBER” 对应的子字符串),并尝试用 tmp 去匹配模式 val(第 7 行)。由于 val 是一个 symbol(符号)模式,它会无条件匹配,同时还会将 val 绑定到 tmp。
此时 app 匹配成功,所有 and 子模式都匹配完成,因此整个 and 模式匹配成功。同理,一旦 and 匹配成功,or 模式也随之匹配成功,并且不会继续尝试子模式 let(第 8 行)。
我们再考虑另一种情况:如果 obj 不是字符串,或者虽是字符串但格式不符合要求。这种情况下,其中一个 pred 模式(第 3-5 行)会匹配失败,进而导致 and 模式(第 2 行)匹配失败,最终 or 模式(第 1 行)会继续尝试子模式 let(第 8 行)。
首先,let 模式会对 (list "149" 'default) 求值,得到 ("149" default) (即 exprval),随后尝试用 exprval 去匹配模式 val。由于 val 是一个 symbol(符号)模式,它会无条件匹配,同时还会将 val 绑定到 exprval。此时 let 模式匹配成功,整个 or 模式也随之匹配成功。
注意观察:and 和 let 这两个子模式的结束方式完全一致 ——都是尝试(且总能成功)匹配 symbol 模式 val,并在这个过程中完成对 val 的绑定。因此,or 模式总能匹配成功,程序控制权也总会转移到分支的主体代码(第 9 行)。由于这行代码是 pcase 匹配成功的分支中最后一个主体形式,它的求值结果会成为 pcase 的返回值,同时也是 grok/pcase 函数的返回值(see 什么是函数?)。
前面的示例都用到了序列模式,并且都以某种方式包含了符号子模式 symbol。 下面是关于这种用法的一些重要细节。
eq 进行相等性判断。
下面的示例展示了一个 pcase 结构,包含两个分支与两个序列模式 A 和 B。A 和 B 都会先检查 expval 是否为序对(使用 pred),然后分别将符号绑定到 expval 的 car 和 cdr(各使用一个 app)。
对于模式 A,由于符号 st 被提及两次,第二次出现会变成用 eq 进行相等判断。而模式 B 使用了两个不同的符号 s1 和 s2,它们都会成为独立的绑定。
(defun grok (object)
(pcase object
((and (pred consp) ; seqpat A
(app car st) ; first mention: st
(app cdr st)) ; second mention: st
(list 'eq st))
((and (pred consp) ; seqpat B
(app car s1) ; first mention: s1
(app cdr s2)) ; first mention: s2
(list 'not-eq s1 s2))))
(let ((s "yow!")) (grok (cons s s))) ⇒ (eq "yow!") (grok (cons "yo!" "yo!")) ⇒ (not-eq "yo!" "yo!") (grok '(4 2)) ⇒ (not-eq 4 (2))
and、符号模式 symbol 和 guard:
(defun square-double-digit-p/CLEAN (integer)
(pcase (* integer integer)
((and n (guard (< 9 n 100))) (list 'yes n))
(sorry (list 'no sorry))))
(square-double-digit-p/CLEAN 9) ⇒ (yes 81)
(square-double-digit-p/CLEAN 3) ⇒ (no 9)
(defun square-double-digit-p/MAYBE (integer)
(pcase (* integer integer)
((and n (guard (< 9 (incf n) 100))) (list 'yes n))
(sorry (list 'no sorry))))
(square-double-digit-p/MAYBE 9) ⇒ (yes 81)
(square-double-digit-p/MAYBE 3) ⇒ (yes 9) ; WRONG!
二者的区别在于 guard 中的布尔表达式 boolean-expression:CLEAN 对 n 的引用简洁且直接,而 MAYBE 在表达式 (incf n) 中引用 n 时带有副作用。
当 integer 的值为 3 时,会发生以下过程:
n 会将其绑定到 expval(即对 (* 3 3) 求值的结果,也就是 9)。
start: (< 9 (incf n) 100) becomes: (< 9 (setq n (1+ n)) 100) becomes: (< 9 (setq n (1+ 9)) 100)
becomes: (< 9 (setq n 10) 100)
; side-effect here!
becomes: (< 9 n 100) ; n now bound to 10
becomes: (< 9 10 100)
becomes: t
nil,
因此 guard 匹配成功,and 也匹配成功,程序流程进入该分支的主体代码。
且不说从数学上判定 9 是两位数本身就是错误的,MAYBE 还存在另一个问题。主体代码再次引用了 n,但我们完全看不到更新后的值 — 10。这到底是怎么回事?
总而言之,最好完全避免对 symbol 模式进行带副作用的引用,不仅是在 boolean-expression(在 guard 中),也包括在 expr(在 let 中)和 function(在 pred 和 app 中)里。
and 时,该集合是其所有子模式各自绑定符号的并集。这是合理的,因为 and 要匹配成功,所有子模式都必须匹配。
当序列模式 seqpat 为 or 时,情况则不同:or 会在第一个匹配成功的子模式处停止,其余子模式会被忽略。如果每个子模式绑定不同的符号集合,这是没有意义的,因为主体代码无法区分究竟是哪个子模式匹配成功,从而无法选择对应的符号集合。
例如,下面的写法是不合法的:
(require 'cl-lib)
(pcase (read-number "Enter an integer: ")
((or (and (pred cl-evenp)
e-num) ; bind e-num to expval
o-num) ; bind o-num to expval
(list e-num o-num)))
Enter an integer: 42 error→ Symbol’s value as variable is void: o-num
Enter an integer: 149 error→ Symbol’s value as variable is void: e-num
对主体代码 (list e-num o-num) 进行求值会触发错误。若要区分不同子模式,你可以使用另一个符号 ——该符号在所有子模式中的名称完全相同,但绑定的值不同。重构上述示例如下:
(require 'cl-lib) (pcase (read-number "Enter an integer: ") ((and num ; line 1 (or (and (pred cl-evenp) ; line 2 (let spin 'even)) ; line 3 (let spin 'odd))) ; line 4 (list spin num))) ; line 5
Enter an integer: 42 ⇒ (even 42)
Enter an integer: 149 ⇒ (odd 149)
第 1 行通过 and 和符号模式 symbol(本例中为 num)将 expval 的绑定 “抽离出来(factors out)”。第 2 行的 or 开头部分与之前一致,但它没有绑定不同的符号,而是两次使用 let(第 3-4 行),在两个子模式中绑定了同一个符号 spin。spin 的值可用于区分不同的子模式。分支的主体代码会引用这两个符号(第 5 行)。
pcase ¶pcase 宏支持多种模式(see 模式匹配条件)。你可以通过 pcase-defmacro 宏为其添加对其他模式类型的支持。
为 pcase 定义一种新的模式类型,该模式可通过 (name actual-args) 的形式调用。
pcase 宏会将该调用展开为一个函数调用,并在这个函数调用中执行 body 的求值逻辑;而 body 的核心作用是:在 args 绑定到 actual-args 的环境中,将被调用的这个新模式重写为其他已有的模式。
此外,该宏还会把 doc 文档信息整合到pcase 的文档字符串中一并展示。按照惯例,doc 中应使用 EXPVAL来指代对 expression(pcase 的第一个参数)求值后的结果。
通常情况下,body 会将被调用的模式重写为更基础的模式。尽管所有模式最终都会被归约为核心模式,但 body 不必直接使用核心模式。
下面的示例定义了两个模式,分别名为 less-than 和 integer-less-than。
(pcase-defmacro less-than (n) "Matches if EXPVAL is a number less than N." `(pred (> ,n)))
(pcase-defmacro integer-less-than (n)
"Matches if EXPVAL is an integer less than N."
`(and (pred integerp)
(less-than ,n)))
注意,这些文档字符串以常规方式提及了 args(在本例中只有一个:n),并且按照惯例也提及了 EXPVAL。
第一次重写(即 less-than 对应的 body)使用了一种核心模式:pred。
第二次重写使用了两种核心模式:and 和 pred,以及刚刚定义的新模式 less-than。
两者都使用了单个反引号结构(see 反引号)。
本小节介绍 反引号风格模式(backquote-style patterns),这是一组内置模式,能够简化结构化匹配。相关背景知识见 see 模式匹配条件。
反引号风格模式是 pcase 中一组功能强大的模式扩展(通过 pcase-defmacro 实现),可以方便地根据 结构 对 expval 进行匹配。
例如,要匹配必须是含两个元素的列表、第一个元素是指定字符串、第二个元素可以是任意值的 expval,可以用核心模式这样写:
(and (pred listp)
ls
(guard (= 2 (length ls)))
(guard (string= "first" (car ls)))
(let second-elem (cadr ls)))
或者你也可以编写等价的反引号风格模式:
`("first" ,second-elem)
反引号风格模式更加简洁,与 expval 的结构相似,并且无需绑定 ls。
反引号风格模式的形式为 `qpat,其中 qpat 可以是以下几种形式:
(qpat1 . qpat2)当 expval 是一个序对(cons cell),并且其 car 匹配 qpat1、cdr 匹配 qpat2 时,匹配成功。这种形式可以很自然地推广到列表,如
(qpat1 qpat2 …)。
[qpat1 qpat2 … qpatm]当 expval 是一个长度为 m 的向量(vector),并且其第 0 到第 (m-1) 个元素分别匹配 qpat1、qpat2、…、qpatm 时,匹配成功。
symbolkeywordnumberstring当 expval 的对应元素与指定的字面量对象(literal object)满足 equal 相等性时,匹配成功。
,pattern当 expval 的对应元素匹配 pattern 时,匹配成功。注意,pattern 可以是 pcase 支持的任意类型的模式。(在上面的示例中,second-elem 是一个核心 symbol 模式;因此它能匹配任意值,并通过 let 绑定 second-elem。)
对应元素(corresponding element) 指的是:expval 中,与反引号风格模式里 qpat 所处结构位置完全相同的那一部分。(在上面的示例中,second-elem 的对应元素就是 expval 的第二个元素。)
以下是一个使用 pcase 为简易表达式语言实现解释器的示例(注意:这要求 fn 分支中的 lambda 表达式启用词法绑定(lexical binding),才能正确捕获 body 和 arg(see 词法绑定):
(defun evaluate (form env)
(pcase form
(`(add ,x ,y) (+ (evaluate x env)
(evaluate y env)))
(`(call ,fun ,arg) (funcall (evaluate fun env)
(evaluate arg env)))
(`(fn ,arg ,body) (lambda (val)
(evaluate body (cons (cons arg val)
env))))
((pred numberp) form)
((pred symbolp) (cdr (assq form env)))
(_ (error "Syntax error: %S" form))))
前三个分支使用了反引号风格模式。
`(add ,x ,y) 这个模式会检查 form 是否为一个以符号 add 开头的三元素列表,然后提取第二个和第三个元素,并将它们分别绑定到符号 x 和 y。这一过程称为解构(destructuring),详见 使用 pcase 模式进行解构。分支主体会对 x 和 y 求值并将结果相加。
类似地,call 分支实现了函数调用,fn 分支实现了匿名函数定义。
剩下的分支使用核心模式。
(pred numberp) 在 form 为数字时匹配成功,匹配成功后,主体会对其直接求值。
(pred symbolp) 在 form 为符号时匹配成功,匹配成功后,主体会在 env 中查找该符号并返回其绑定值。
最后,_ 是通配模式,可以匹配任何内容,因此适合用来报告语法错误。
下面是这个小型语言中的几个示例程序,以及它们的求值结果:
(evaluate '(add 1 2) nil) ⇒ 3 (evaluate '(add x y) '((x . 1) (y . 2))) ⇒ 3 (evaluate '(call (fn x (add 1 x)) 2) nil) ⇒ 3 (evaluate '(sub 1 2) nil) ⇒ error
pcase 模式进行解构 ¶Pcase 模式不仅能对可匹配对象的结构表达条件,还能提取这些对象的子字段。例如,我们可以通过下面的代码,从变量 my-list 对应的列表中提取 2 个元素:
(pcase my-list
(`(add ,x ,y) (message "Contains %S and %S" x y)))
这段文本的精准简体中文翻译如下(贴合编程技术文档风格,术语统一且语义完整):
这一操作不仅会提取出 x 和 y,还会额外验证 my-list 是否为恰好包含 3 个元素且第一个元素是符号 add 的列表。如果这些验证中有任意一项失败,pcase 会立即返回 nil,且不会调用 message 函数。
从一个对象中提取其存储的多个值的操作被称为 解构(destructuring)。使用 pcase 模式可以实现 解构绑定(destructuring binding)—— 这种绑定方式与局部绑定(see 局部变量)类似,但它并非简单赋值,而是通过从结构匹配的对象中提取值,为一个变量的多个元素分别赋予对应值。
本节所描述的宏会借助 pcase 模式来执行解构绑定。“对象需具备兼容结构” 这一条件,意味着该对象必须匹配对应的模式—— 只有满足这一条件,才能提取出对象的子字段。例如:
(pcase-let ((`(add ,x ,y) my-list))
(message "Contains %S and %S" x y))
其作用与前面的示例相同,区别在于:它会直接尝试从 my-list 中提取 x 和 y,而不会先检查 my-list 是否为列表、元素数量是否正确,以及首元素是否为 add。
当对象实际并不匹配模式时,具体行为取决于数据类型,但主体代码不会被静默跳过:要么会抛出错误,要么会执行主体,但部分变量会被绑定到 nil 之类的任意值。
例如,上面的模式会通过 car 或 nth 这类操作提取 x 和 y,因此当 my-list 长度不足时,它们会得到 nil。与之相对,如果使用类似 `[add ,x ,y] 这样的模式,这些变量会通过 aref 提取,一旦 my-list 不是数组或长度不足,就会抛出错误。
适用于解构绑定的 pcase 模式通常就是 反引号风格模式 中介绍的那些,因为它们明确描述了待匹配对象的结构规范。
如需了解解构绑定的另一种实现方式,可参见 seq-let。
根据 bindings 对变量执行解构绑定,随后对 body 进行求值。
bindings 是一个绑定列表,其中每个绑定项的形式为 (pattern exp) — exp 是待求值的表达式,pattern 是一个 pcase 模式。
所有 exp 会先被求值,之后将其与各自对应的 pattern 进行匹配;匹配完成后会生成新的变量绑定,这些变量可在 body 中使用。变量绑定的生成逻辑是:将 pattern 中的元素解构绑定到已求值的 exp 对应元素的值上。
以下是一个简单示例:
(pcase-let ((`(,major ,minor)
(split-string "image/png" "/")))
minor)
⇒ "png"
根据 bindings 对变量执行解构绑定,随后对 body 进行求值。
bindings 是一个绑定列表,其中每个绑定项的形式为 (pattern exp) — exp 是待求值的表达式,pattern 是一个 pcase 模式。变量绑定的生成逻辑为:将 pattern 中的元素解构绑定到已求值的 exp 对应元素的值上。
与 pcase-let 不同(但与 let* 类似),在处理 bindings 的下一个元素之前,会先将每个 exp 与其对应的 pattern 完成匹配。因此,bindings 中前序绑定项所生成的变量,不仅可在 body 中使用,还能在后续绑定项的 exp 表达式中使用。
针对 list 中的每个元素执行一次 body;在每次迭代时,会将 pattern 中的变量解构绑定到 list 当前元素对应子字段的值上。这些绑定的执行逻辑与 pcase-let 一致。当 pattern 是一个简单变量时,该宏的效果等价于 dolist(see 迭代)。
以 setq 的形式为变量赋值,同时会根据每个 pattern(各自对应的模式)对 value 执行解构操作。
该宏的作用与 lambda 类似,但允许每个参数都作为一个模式使用。例如,以下是一个接收序对(cons cell)作为参数的简单函数:
(setq fun
(pcase-lambda (`(,key . ,val))
(vector key (* val 10))))
(funcall fun '(foo . 2))
⇒ [foo 20]
迭代是指重复执行程序的某一部分。例如,你可能想对列表中的每个元素执行一次计算,或者对从 0 到 n 的每个整数各执行一次。在 Emacs Lisp 中,可以使用特殊形式 while 来实现:
while 首先对 condition(条件)求值。如果结果为非 nil,则按文本顺序依次执行 forms(语句体)。然后它会再次对条件求值,如果结果仍为非 nil,则再次执行语句体。这一过程会不断重复,直到 condition 求值结果为 nil。
迭代次数没有限制。循环会一直执行,直到条件求值为 nil,或者发生错误、或通过 throw 跳出循环为止(see 非局部退出)。
while 形式的返回值永远是 nil。
(setq num 0)
⇒ 0
(while (< num 4)
(princ (format "Iteration %d." num))
(setq num (1+ num)))
⊣ Iteration 0.
⊣ Iteration 1.
⊣ Iteration 2.
⊣ Iteration 3.
⇒ nil
要编写先执行循环体、后判断条件的 repeat-until 循环,可以将循环体 + 结束判断放在一个 progn 里,并作为 while 的第一个参数,如下所示:
(while (progn
(forward-line 1)
(not (looking-at "^$"))))
该代码会向下移动一行,并持续按行移动,直到抵达空行。这段代码的特殊之处在于:while 没有独立的循环体,仅包含结束判断(而该判断同时完成了移动光标(point)的实际操作)。
dolist 和 dotimes 宏为两种常见循环类型提供了简洁的实现方式。
该结构会针对 list 中的每个元素执行一次 body,并将变量 var 局部绑定为当前遍历到的元素。执行完成后,它会返回 result 的求值结果;若省略 result,则返回 nil。例如,以下是使用 dolist 定义 reverse 函数的方式:
(defun reverse (list)
(let (value)
(dolist (elt list value)
(setq value (cons elt value)))))
该结构会针对从 0(包含)到 count(不包含)的每个整数执行一次 body,并将变量 var 绑定为当前迭代对应的整数。执行完成后,它会返回 result 的求值结果;若省略 result,则返回 nil。不建议使用 result 参数。以下是使用 dotimes 执行某操作 100 次的示例:
(dotimes (i 100) (insert "I will not obey absurd orders\n"))
生成器(generator) 是一种能够生成潜在无限值序列的函数。该函数每生成一个值后,会暂停自身执行,等待调用方请求下一个值。
iter-defun 用于定义一个生成器函数。生成器函数的签名与普通函数一致,但执行逻辑不同:调用生成器函数时,并不会立即执行 body(函数体),而是返回一个迭代器对象。这个迭代器会运行 body 来生成值 —— 每当执行到 iter-yield 或 iter-yield-from 处,迭代器会输出一个值并暂停执行。当 body 正常返回时,iter-next 会触发 iter-end-of-sequence 信号,并将 body 的返回结果作为该信号的条件数据。
body 中可以编写任意合法的 Lisp 代码,但 iter-yield 和 iter-yield-from 不能出现在 unwind-protect 形式内部。
iter-lambda 用于创建一个匿名生成器函数,其工作方式与通过 iter-defun 创建的生成器函数完全一致。
当 iter-yield 出现在生成器函数内部时,它会指示当前迭代器暂停执行,并将 value 作为 iter-next 的返回值。而 iter-yield 本身的求值结果,则是下一次调用 iter-next 时传入的 value 参数。
iter-yield-from 会产出 iterator(迭代器)生成的所有值,其自身的求值结果为 iterator 对应的生成器函数正常返回的值。在 iter-yield-from 掌控执行流程期间,iterator 会接收所有通过 iter-next 发送给该迭代器的值。
使用生成器函数的步骤:首先以常规方式调用生成器函数,得到一个 迭代器(iterator) 对象(迭代器是生成器的一个具体实例);然后通过 iter-next 从该迭代器中获取值。当迭代器中没有更多值可供获取时,iter-next 会抛出 iter-end-of-sequence 条件异常,并将迭代器的最终值作为该异常的附加数据。
需要特别注意的是,生成器函数体仅会在调用 iter-next 时执行。调用通过 iter-defun 定义的函数会生成一个迭代器;只有通过 iter-next 驱动这个迭代器,才会触发有实际意义的执行逻辑。
每次调用生成器函数,都会生成一个 独立 的迭代器,且每个迭代器都拥有自身的状态。
从 iterator(迭代器)中获取下一个值。若已无更多可生成的值(即迭代器对应的生成器函数已返回),iter-next 会触发 iter-end-of-sequence 条件异常;该异常关联的附加数据,即为迭代器 iterator 对应的生成器函数的返回值。
value 会被传入迭代器,并成为 iter-yield 的求值结果。对于某个迭代器的第一次 iter-next 调用,value 会被忽略 ——因为在迭代器对应的生成器函数启动之初,生成器函数尚未执行到任何 iter-yield 形式。
若 iterator(迭代器)暂停于 unwind-protect 的 bodyform(主体代码)内部,且变得无法被访问,Emacs 会在一次垃圾回收过程后最终执行 unwind 处理函数。(注意:iter-yield 在 unwind-protect 的 unwindforms(清理代码)内部是不合法的。)如需确保这些处理函数在此之前执行,可调用 iter-close。
Emacs 提供了一些便捷函数来简化迭代器的使用:
依次将 var 绑定为 iterator 生成的每个值,并执行 body(代码体)。
Common Lisp 循环工具也包含用于操作迭代器的特性,see Loop Facility in Common Lisp Extensions。
以下代码片段演示了使用迭代器的一些核心原则。
(require 'generator)
(iter-defun my-iter (x)
(iter-yield (1+ (iter-yield (1+ x))))
;; Return normally
-1)
(let* ((iter (my-iter 5))
(iter2 (my-iter 0)))
;; Prints 6
(print (iter-next iter))
;; Prints 9
(print (iter-next iter 8))
;; Prints 1; iter and iter2 have distinct states
(print (iter-next iter2 nil))
;; We expect the iter sequence to end now
(condition-case x
(iter-next iter)
(iter-end-of-sequence
;; Prints -1, which my-iter returned normally
(print (cdr x)))))
非局部退出(nonlocal exit) 是指将程序的控制流从一个位置直接转移到另一个较远的位置。在 Emacs Lisp 中,非局部退出可能因错误而触发,你也可以显式地使用它们。非局部退出会解除被退出结构所建立的所有变量绑定。
catch 和 throw ¶大多数控制结构仅影响自身内部的控制流。而函数 throw 是常规程序执行规则中的一个例外:它可以根据请求执行非局部退出。(也存在其他例外,但它们仅用于错误处理。)throw 必须在 catch 内部使用,并会跳转回对应的 catch 处。例如:
(defun foo-outer ()
(catch 'foo
(foo-inner)))
(defun foo-inner ()
...
(if x
(throw 'foo t))
...)
若 throw 结构被执行,它会将控制流直接转移回对应的 catch 处,该 catch 会立即返回。throw 之后的代码不会被执行。throw 的第二个参数会被用作 catch 的返回值。
函数 throw 会根据第一个参数查找匹配的 catch:它会搜索第一个参数与 throw 中指定参数满足 eq 相等性的 catch。若存在多个符合条件的 catch,则最内层的那个优先生效。因此,在上述示例中,throw 指定了 foo,而 foo-outer 中的 catch 也指定了同一个符号,所以该 catch 就是匹配的目标(假设两者之间没有其他匹配的 catch)。
执行 throw 会退出直至匹配 catch 为止的所有 Lisp 结构,包括函数调用。当 let 等绑定结构或函数调用以这种方式退出时,其建立的绑定会被解除 ——这与这些结构正常退出时的行为完全一致(see 局部变量)。同理,throw 会恢复由 save-excursion 保存的缓冲区和光标位置(see Excursions),以及由 save-restriction 保存的缓冲区缩窄状态。此外,当 throw 退出 unwind-protect 特殊形式时,还会执行该形式所设置的所有清理操作(see 非局部退出的清理工作)。
throw 并不需要在词法上出现在它所跳转的 catch 内部。它同样可以从 catch 内部调用的另一个函数中被执行。只要 throw 的执行时机,在时间顺序上处于进入 catch 之后、退出 catch 之前,它就能够找到并跳转到该 catch。这也是为什么 throw 可以用在诸如 exit-recursive-edit 这类命令中,用于跳转回编辑器命令循环(see 递归编辑)。
Common Lisp 注意: 大多数其他 Lisp 方言(包括 Common Lisp)提供了多种非顺序控制转移的方式,例如
return、return-from和go。而 Emacs Lisp 只提供了throw。cl-lib 库提供了其中一部分的实现。See Blocks and Exits in Common Lisp Extensions。
catch 会为 throw 函数建立一个返回点。该返回点通过 tag(标记)与其他返回点区分开,tag 可以是除 nil 之外的任意 Lisp 对象。在建立返回点之前,参数 tag 会先被正常求值。
当返回点生效后,catch 会按文本顺序对 body(代码体)中的形式依次求值。如果这些形式正常执行(无错误、无非局部退出),则 catch 会返回 body 中最后一个形式的求值结果。
若在 body 执行期间触发了 throw,且该 throw 指定的标记值与 tag 相同,则 catch 形式会立即退出;其返回值为 throw 的第二个参数所指定的值。
throw 的作用是从先前通过 catch 建立的返回点中返回。参数 tag(标记)用于从多个已存在的返回点中选择匹配的目标;它必须与 catch 中指定的标记值满足 eq 相等性。若有多个返回点匹配该 tag,则使用最内层的那个返回点。
参数 value 会被用作对应 catch 的返回值。
如果当前不存在标记为 tag 且生效的返回点,Emacs 会触发 no-catch 错误,并将 (tag value) 作为该错误的附加数据。
catch 和 throw 的示例 ¶使用 catch 和 throw 的一种场景是退出双层嵌套循环。(在大多数编程语言中,这类需求会通过 goto 实现。)以下示例中,我们会计算当 i 和 j 从 0 遍历到 9 时 (foo i j) 的值:
(defun search-foo ()
(catch 'loop
(let ((i 0))
(while (< i 10)
(let ((j 0))
(while (< j 10)
(if (foo i j)
(throw 'loop (list i j)))
(setq j (1+ j))))
(setq i (1+ i))))))
若 foo 某次返回值为非 nil,则会立即终止执行,并返回一个包含 i 和 j 的列表。若 foo 始终返回 nil,则 catch 会正常返回,其返回值为 nil—— 因为这正是 while 结构的执行结果。
以下是两个稍有差异的进阶示例,展示了同时存在两个返回点的场景。首先是两个返回点使用相同标记 hack 的情况:
(defun catch2 (tag)
(catch tag
(throw 'hack 'yes)))
⇒ catch2
(catch 'hack (print (catch2 'hack)) 'no) ⊣ yes ⇒ no
由于两个返回点的标记均与该 throw 匹配,因此 throw 会跳转到内层的那个返回点 —— 也就是在 catch2 中建立的返回点。因此,catch2 会正常返回,返回值为 yes,且该值会被打印输出。最后,外层 catch 代码体中的第二个形式(即 'no)会被求值,并作为外层 catch 的返回值。
接下来我们修改传给 catch2 的参数:
(catch 'hack (print (catch2 'quux)) 'no) ⇒ yes
我们仍然有两个返回点,但这一次只有外层返回点的标记是 hack;内层返回点的标记改为了 quux。因此,throw 会让外层的 catch 直接返回 yes。函数 print 不会被调用,代码体 'no 也不会被求值。
当 Emacs Lisp 试图对某个因某种原因无法被求值的形式进行求值时,它会 发出(signal) 一个 错误(error)。
当错误被发出时,Emacs 的默认处理方式是:打印错误信息,并终止当前命令的执行。在大多数情况下这都是正确的行为,例如你在缓冲区末尾按下 C-f 时。
在复杂的程序中,简单地终止执行往往不是你想要的结果。例如,程序可能已经对数据结构做了临时修改,或是创建了临时缓冲区,这些都需要在程序结束前清理掉。这时,你可以使用 unwind-protect 来设置 清理表达式(cleanup expressions),以便在发生错误时执行。(See 非局部退出的清理工作。)偶尔,你可能希望即使子程序出错,程序仍能继续运行。在这些情况下,可以使用 condition-case 来设置 错误处理函数(error handlers),以便在出错时重新获得程序控制权。
如果你只想报告问题,而不终止当前命令的执行,可以考虑发出一条警告。See Reporting Warnings。
请不要使用错误处理机制来在程序的不同部分之间转移控制;这种场景应当使用 catch 和 throw。See 显式非局部退出:catch 和 throw。
发出(signaling) 错误,指的是启动错误处理流程。错误处理通常会中止正在运行的程序的全部或部分,并返回到预先设置好用于处理错误的位置(see 如何处理错误)。这里我们介绍如何主动发出错误。
大多数错误是在你调用的 Lisp 基本函数内部自动发出的,比如你试图对一个整数取 CAR,或者在缓冲区末尾尝试向前移动字符时。你也可以使用函数 error 和 signal 显式地发出错误。
当用户按下 C-g 时触发的退出(Quitting),不算作错误,但其处理方式与错误几乎相同。See 退出。
所有错误都会以这样或那样的方式指定一条错误消息。消息应当说明哪里出了问题(例如 “File does not exist”),而非事情 “应该是怎样的”(例如 “File must exist”)。Emacs Lisp 中的约定是:错误消息应以大写字母开头,但不应以任何形式的标点符号结尾。
该函数会触发一个错误,其错误消息是通过将 format-message(see 格式化字符串)作用于 format-string(格式字符串)和 args(参数列表)构建而成。
以下示例展示了 error 的典型用法:
(error "That is an error -- try something else")
error→ That is an error -- try something else
(error "Invalid name `%s'" "A%%B")
error→ Invalid name ‘A%%B’
error 函数的实现逻辑是调用 signal 并传入两个参数:错误符号 error,以及一个包含 format-message 返回字符串的列表。
格式字符串中的重音符和撇号,通常会被转换为配对的弯引号,例如 "Missing `%s'" 可能会被转换为 "Missing ‘foo’".。关于如何调整或禁止这种转换方式,详见 See 文本引用样式。
警告: 如果你希望原封不动地使用自定义字符串作为错误消息,不要直接编写 (error string)。若 string 中包含 ‘%’、‘`’ 或 ‘'’,该字符串可能会被重新格式化,从而产生不符合预期的结果。正确的写法是使用 (error "% s" string)。
当 noninteractive 的值为非 nil 时(see Batch Mode),若触发的错误没有对应的处理函数,该函数会终止 Emacs 进程。
该函数会触发一个以 error-symbol(错误符号)命名的错误。参数 data 是一个列表,包含与该错误场景相关的其他 Lisp 对象。
参数 error-symbol 必须是一个 错误符号(error symbol) — 即通过 define-error 定义的符号。Emacs Lisp 正是通过这种方式对不同类型的错误进行分类。关于错误符号、错误条件及条件名的详细说明,see 错误符号与条件名称。
若该错误未被处理,则这两个参数会被用于打印错误消息。通常情况下,错误消息由 error-symbol 的 error-message 属性提供。若 data 为非 nil 值,则消息末尾会追加一个冒号,并跟上 data 中未经求值的元素组成的逗号分隔列表。对于 error 类型的错误,其错误消息为 data 的 CAR 部分(该部分必须是字符串)。file-error 的子类别会被特殊处理。
data 列表中对象的数量和含义由 error-symbol 决定。例如,对于 wrong-type-argument 错误,列表中应包含两个对象:一个用于描述期望类型的断言(谓词),以及一个不符合该类型的对象。
error-symbol(错误符号)和 data(附加数据)均可被处理该错误的所有错误处理函数访问:condition-case 会将一个局部变量绑定为形如 (error-symbol . data) 的列表(see 编写处理错误的代码)。
signal 函数永远不会返回。
若 error-symbol 对应的错误没有处理函数,且 noninteractive 的值为非 nil(see Batch Mode),该函数最终会终止 Emacs 进程。
(signal 'wrong-number-of-arguments '(x y))
error→ Wrong number of arguments: x, y
(signal 'no-such-error '("My unknown error condition"))
error→ peculiar error: "My unknown error condition"
该函数的行为与 error 完全一致,唯一区别是它使用错误符号 user-error 而非 error。顾名思义,该函数用于报告用户操作引发的错误,而非代码本身的错误。例如,若你尝试使用 Info-history-back 命令(快捷键 l)回退到 Info 浏览历史的起始位置之前,Emacs 会触发一个 user-error 错误。这类错误不会触发调试器,即便 debug-on-error 的值为非 nil 也是如此。
See 发生错误时进入调试器。
Common Lisp 注意: Emacs Lisp 中没有类似于 Common Lisp 里可继续错误的概念。
当发出一个错误时,signal 会为该错误寻找一个当前有效的 处理程序(handler)。处理程序是一段 Lisp 表达式,用于在程序的某一部分发生错误时执行。
如果该错误存在可用的处理程序,就会执行该处理程序,然后控制流在处理程序之后继续执行。处理程序在建立它的 condition-case 所在的环境中执行;在该 condition-case 内部调用过的所有函数都已经退出,处理程序无法返回到这些函数中。
如果该错误没有可用的处理程序,则会终止当前命令,并将控制权交还给编辑器命令循环。(命令循环内置了一个可处理所有类型错误的隐式处理程序。)命令循环的处理程序会利用错误符号及关联数据来打印错误消息。你可以通过变量 command-error-function 来控制这一处理过程:
若该变量的值为非 nil,则指定了一个用于处理 “将控制权交还 Emacs 命令循环” 类错误的函数。该函数需接收三个参数:
data:格式与 condition-case 绑定到其变量的列表相同;
context:描述错误发生场景的字符串,(更常见的情况是)值为 nil;
caller:调用了触发该错误的基本函数的那个 Lisp 函数。
无显式处理程序的错误可能会调用 Lisp 调试器(see 调用调试器)。当变量 debug-on-error(see 发生错误时进入调试器)的值为非 nil 时,调试器会被启用。与错误处理程序不同,调试器会在错误发生的环境中运行,因此你可以精准查看错误发生时各变量的取值。在批处理模式下(see Batch Mode),Emacs 进程通常会以非零退出状态终止。
发出错误的通常效果是终止正在运行的命令,并立即返回到 Emacs 编辑器的命令循环。你可以通过使用特殊形式 condition-case 建立错误处理程序,来捕获程序某一部分中发生的错误。
一个简单的示例如下:
(condition-case nil
(delete-file filename)
(error nil))
这段代码会删除名为 filename 的文件,并捕获所有可能出现的错误;若发生错误,则返回 nil。(对于这类简单场景,你可以使用宏 ignore-errors 来实现;详见下文。)
condition-case 结构常被用于捕获可预见的错误,例如调用 insert-file-contents 时打开文件失败的情况。它也可用于捕获完全不可预见的错误,比如程序对从用户处读取的表达式进行求值时产生的错误。
condition-case 的第二个参数被称为受保护形式(protected form)。(在上述示例中,受保护形式是对 delete-file 的调用。)当该形式开始执行时,错误处理程序即刻生效;当该形式执行完毕返回时,错误处理程序便会失效。在这期间的所有时刻,错误处理程序均保持生效状态。具体来说,在该形式调用的函数、这些函数的子例程等的执行过程中,错误处理程序都处于生效状态。这是一个很实用的特性,因为严格来讲,错误只能由受保护形式调用的 Lisp 基本函数(包括 signal 和 error)触发,而非受保护形式本身。
受保护形式之后的参数均为处理程序。每个处理程序会列出一个或多个 条件名(condition names)(即符号),用于指定它能处理的错误类型。触发错误时指定的错误符号也会定义一个条件名列表。只要处理程序与错误有任一共同的条件名,该处理程序就适用于此错误。在上述示例中,仅有一个处理程序,它指定了一个条件名 error,该条件名可覆盖所有类型的错误。
查找可用处理程序时,会从最近建立的处理程序开始,检查所有已建立的处理程序。因此,若两个嵌套的 condition-case 结构都声明要处理同一错误,则内层的那个会优先处理该错误。
若某个错误被某一 condition-case 结构处理,通常会阻止调试器运行 —— 即便 debug-on-error 配置要求该错误触发调试器也是如此。
若你希望能够调试被 condition-case 捕获的错误,可将变量 debug-on-signal 设置为非 nil 值。你也可以为特定处理程序指定先运行调试器,只需在条件列表中写入 debug 即可,示例如下:
(condition-case nil
(delete-file filename)
((debug error) nil))
此处 debug 的作用仅为阻止 condition-case 抑制对调试器的调用。任何给定的错误是否会触发调试器,仍取决于 debug-on-error 及其他常规过滤机制的设置。See 发生错误时进入调试器。
宏 condition-case-unless-debug 提供了另一种对这类表达式进行调试的方式。它的行为与 condition-case 完全一致,除非变量 debug-on-error 不为 nil,此时它将完全不处理任何错误。
一旦 Emacs 判定某个处理函数负责处理该错误,就会将控制权转交给该处理函数。为此,Emacs 会解除所有在退出过程中由绑定结构创建的变量绑定,并执行所有正在退出的 unwind-protect 表达式的清理操作。当控制权到达处理函数时,处理函数的主体将正常执行。
处理函数主体执行完毕后,执行流程从 condition-case 表达式返回。由于受保护表达式在处理函数执行前已完全退出,处理函数无法在错误发生点恢复执行,也无法访问受保护表达式内部建立的变量绑定。它只能完成清理工作并继续执行。
错误的抛出与处理和 throw 与 catch 有几分相似(see 显式非局部退出:catch 和 throw),但它们是完全独立的两套机制。错误无法被 catch 捕获,而 throw 也无法被错误处理函数处理(尽管在没有匹配 catch 的情况下执行 throw 会抛出一个可以被处理的错误)。
这个特殊形式会在 protected-form 执行期间,建立起错误处理函数 handlers。如果 protected-form 执行时没有发生错误,它的返回值就会成为 condition-case 形式的值(在没有成功处理函数的情况下;见下文)。在这种情况下,condition-case 不会产生任何效果。只有当 protected-form 执行过程中发生错误时,condition-case 才会发挥作用。
每个 handlers 都是形如 (conditions body…) 的列表。其中 conditions 是要处理的错误条件名,或是一个条件名列表(可以包含 debug,以便在处理函数执行前先运行调试器)。条件名 t 可以匹配任意条件。body 是当该处理函数捕获到错误时要执行的一条或多条 Lisp 表达式。下面是处理函数的示例:
(error nil) (arith-error (message "Division by zero")) ((arith-error file-error) (message "Either division by zero or failure to open a file"))
发生的每个错误都带有一个 错误符号(error symbol),用于描述错误类型,同时也对应一组条件名称列表(see 错误符号与条件名称)。Emacs 会在所有生效的 condition-case 形式中,查找指定了这些条件名称之一的处理函数;最内层匹配的 condition-case 负责处理该错误。在这个 condition-case 内部,第一个匹配的处理函数处理该错误。
执行完处理函数的主体后,condition-case 会正常返回,并以处理函数主体中最后一个表达式的值作为整体返回值。
参数 var 是一个变量。condition-case 在执行 protected-form 时不会绑定该变量,只有在处理错误时才会绑定。此时,它会将 var 局部绑定到一个 错误描述(error description) 上,这是一个包含错误具体信息的列表。错误描述的格式为 (error-symbol . data)。处理函数可以引用这个列表来决定后续操作。例如,如果错误是打开文件失败,那么文件名就是 data 的第二个元素 — 也就是错误描述的第三个元素。
如果 var 为 nil,则表示不绑定任何变量。此时处理函数无法获取错误符号及其相关数据。
作为一种特殊情况,handlers 中可以包含一个格式为 (:success body…) 的处理项。当 protected-form 无错误正常结束时,会执行这里的 body,并且(如果 var 非空)会把 var 绑定到 protected-form 的返回值上。
有时需要将被 condition-case 捕获的信号重新抛出,以便让更外层的处理函数捕获。做法如下:
(signal (car err) (cdr err))
其中 err 是错误描述变量,即 condition-case 的第一个参数,你希望重新抛出该参数对应的错误条件。
See Definition of signal。
该函数返回给定错误描述符对应的错误消息字符串。如果你希望通过打印该错误对应的常规错误消息来处理错误,这个函数会非常有用。See Definition of signal。
以下是一个使用 condition-case 处理除以零导致的错误的示例。该处理函数会显示错误消息(但不发出提示音),然后返回一个极大的数值。
(defun safe-divide (dividend divisor)
(condition-case err
;; Protected form.
(/ dividend divisor)
;; The handler. (arith-error ; Condition. ;; Display the usual message for this error. (message "%s" (error-message-string err)) 1000000))) ⇒ safe-divide
(safe-divide 5 0)
⊣ Arithmetic error: (arith-error)
⇒ 1000000
该处理函数指定了条件名 arith-error,因此它只处理除以零的错误。其他类型的错误不会被(这个 condition-case)捕获处理。因此:
(safe-divide nil 3)
error→ Wrong type argument: number-or-marker-p, nil
这里是一个能够捕获所有类型错误(包括来自 error 的错误)的 condition-case 示例:
(setq baz 34)
⇒ 34
(condition-case err
(if (eq baz 35)
t
;; This is a call to the function error.
(error "Rats! The variable %s was %s, not 35" 'baz baz))
;; This is the handler; it is not a form.
(error (princ (format "The error was: %s" err))
2))
⊣ The error was: (error "Rats! The variable baz was 34, not 35")
⇒ 2
该结构执行 body,并忽略其执行过程中发生的所有错误。如果执行过程中未出现错误,ignore-errors 返回 body 中最后一个表达式的值;若发生错误,则返回 nil。
以下是将本节开头的示例改用 ignore-errors 后的写法:
(ignore-error end-of-file
(read ""))
condition 也可以是一个错误条件列表。
该宏类似于 ignore-errors 的「温和版」。它不会完全抑制错误,而是将错误转换为提示消息。该宏会使用字符串 format 来格式化这条消息。format 中应包含且仅包含一个 ‘%’ 格式序列(例如 "Error: % S")。在那些不预期会抛出错误、但出错时需保证鲁棒性的代码外层,可使用 with-demoted-errors。注意,该宏使用的是 condition-case-unless-debug,而非 condition-case。
有时我们希望捕获部分错误,并记录错误发生时的上下文信息 —— 例如完整的调用栈回溯(backtrace)、当前缓冲区(buffer)等。遗憾的是,这类信息无法在 condition-case 的处理函数中获取:因为在运行处理函数之前,调用栈已被展开(unwound),所以处理函数的执行上下文是 condition-case 所在的动态环境,而非错误抛出的位置。针对这类场景,你可以使用以下形式:
该特殊形式执行 body;若 body 执行过程中未发生错误,其返回值将作为 handler-bind 形式的返回值。这种情况下,handler-bind 不会产生任何作用。
handlers 应为一个列表,其元素格式为 (conditions handler):其中 conditions 是待处理的错误条件名(或条件名列表),handler 则是一个经求值后应返回函数的表达式。与 condition-case 一致,条件名均为符号类型。
在执行 body 之前,handler-bind 会对所有 handler 表达式求值,并将这些处理函数注册为「在 body 求值期间生效」的处理逻辑。当错误被抛出时,Emacs 会遍历所有生效的 condition-case 和 handler-bind 形式,查找指定了该错误对应条件名的处理函数;若最内层匹配的处理函数是由 handler-bind 注册的,则会调用该 handler 函数,并将错误描述作为唯一参数传入。
与 condition-case 的行为相反,handler 是在错误发生的动态上下文中被调用的。这意味着它执行时不会解除任何变量绑定,也不会执行 unwind-protect 的任何清理操作,因此所有这些动态绑定仍然有效。
但有一个例外:在运行 handler 函数期间,从抛出错误的代码到当前 handler-bind 之间的所有错误处理函数都会被临时挂起。这意味着当再次抛出错误时,Emacs 只会查找位于 handler 函数内部,或当前 handler-bind 外部的那些生效的 condition-case 和 handler-bind。
另外请注意,词法绑定变量(see 词法绑定)不受影响,因为它们不具有动态作用域。
与任何普通函数一样,handler 可以非局部退出(通常通过 throw),也可以正常返回。如果 handler 正常返回,则表示该处理函数拒绝处理此错误,系统会从刚才中断的位置继续查找其他错误处理函数。
例如,如果我们想要记录某段代码执行过程中发生的所有错误,以及错误抛出时的当前缓冲区,同时又不影响这段代码原本的行为,就可以使用:
(handler-bind
((error
(lambda (err)
(push (cons err (current-buffer)) my-log-of-errors))))
body-forms...)
这样只会记录那些没有在 body-forms… 内部被捕获、而是从其中 “逃逸(escape)” 出来的错误。并且它不会阻止这些错误继续传递给外层的 condition-case 处理函数(或 handler-bind 处理函数),因为上面的处理函数是正常返回的。
我们还可以使用 handler-bind 将一种错误替换成另一种。例如下面的代码,会把在 body-forms… 执行期间发生的所有 user-error 类型错误,都转换成普通的 error:
(handler-bind
((user-error
(lambda (err)
(signal 'error (cdr err)))))
body-forms...)
我们可以使用 condition-case 达到几乎相同的效果:
(condition-case err
(progn body-forms...)
(user-error (signal 'error (cdr err))))
但区别在于:当我们在 handler-bind 中(重新)抛出新错误时,原错误发生时的动态环境依然保持有效。
这意味着,例如如果此时进入调试器,它会显示完整的调用栈回溯,其中包含原始错误被抛出的位置:
Debugger entered--Lisp error: (error "Oops")
signal(error ("Oops"))
#f(lambda (err) [t] (signal 'error (cdr err)))((user-error "Oops"))
user-error("Oops")
...
eval((handler-bind ((user-error (lambda (err) ...
当你抛出一个错误时,需要指定一个 错误符号(error symbol),用来表明你所指的错误类型。每个错误有且仅有一个错误符号对其进行分类,这是 Emacs Lisp 语言中最精细的错误分类方式。
这些精细的分类又被归入范围更广的 错误条件(error conditions) 层级体系中,由 条件名称(condition names) 标识。其中最精细的分类就是错误符号本身:每个错误符号同时也是一个条件名称。同时也存在覆盖范围更广的条件名称,最顶层的条件名称是 error,它包含所有类型的错误(但不包括 quit)。
因此,每个错误都拥有一个或多个条件名称:error、该错误自身的符号(如果它与 error 不同),以及可能存在的一些中间分类名称。
若要将一个符号定义为错误符号,必须通过 define-error 函数来完成定义 —— 该函数需指定一个父条件(默认值为 error)。这个父条件决定了此类错误所属的条件范畴。父条件的传递闭包集合始终包含错误符号本身,以及符号 error。由于「退出(quitting)」不被视作错误,因此 quit 的父条件集合仅为 (quit)。
除父条件外,错误符号还关联有一个 message(消息字符串):当该错误被抛出但未被处理时,此字符串会被打印。若该消息无效,则会使用错误提示语 ‘peculiar error’(异常错误)。See Definition of signal。
在内部实现中,父条件集合被存储在错误符号的 error-conditions 属性中,而错误消息则存储在错误符号的 error-message 属性中。
以下是定义新错误符号 new-error 的方式:
(define-error 'new-error "A new error" 'my-own-errors)
该错误拥有多个条件名称:最细分的类型 new-error;我们假定的范围更广的分类 my-own-errors;以及 my-own-errors 所继承的所有条件,其中应当包含范围最广的 error。
错误字符串应以大写字母开头,但不应以句号结尾。这是为了与 Emacs 其他部分保持一致。
显然,Emacs 自身永远不会主动抛出 new-error;只有在你的代码中显式调用 signal(see Definition of signal)才能触发该错误:
(signal 'new-error '(x y))
error→ A new error: x, y
可以通过该错误的任意一个条件名称来捕获它。
下面这个示例会处理 new-error 以及属于 my-own-errors 类别的其他所有错误:
(condition-case foo
(bar nil t)
(my-own-errors nil))
错误的主要分类方式是通过条件名称(condition names) — 也就是用于将错误与处理函数匹配的名称。错误符号仅作为一种便捷方式,用来指定对应的错误消息和条件名称列表。如果给 signal 传入一长串条件名称,而不是一个错误符号,会非常繁琐。
相反,如果只使用错误符号、不使用条件名称,会严重削弱 condition-case 的能力。条件名称让你在编写错误处理函数时,可以按不同粒度对错误进行分类。如果只使用错误符号,就只能使用最细粒度的分类,无法进行更粗粒度的归类。
有关主要错误符号及其条件的列表,see Standard Errors。
当你临时将数据结构置于不一致状态时,unwind-protect 结构是必不可少的;它能确保在发生错误或 throw 时,将数据恢复到一致状态。(另一个仅用于缓冲区内容修改的专用清理结构是原子修改组;Atomic Change Groups。)
unwind-protect 执行 body-form,并保证:无论以何种方式退出 body-form,都会执行 cleanup-forms。body-form 可能正常结束、通过 throw 跳出 unwind-protect,或触发错误;在所有情况下,cleanup-forms 都会被执行。
如果 body-form 正常结束,unwind-protect 会在执行完 cleanup-forms 后,返回 body-form 的值。如果 body-form 未正常结束,unwind-protect 就不会按正常方式返回任何值。
只有 body-form 受到 unwind-protect 的保护。如果某个 cleanup-forms 自身发生了非局部退出(通过 throw 或错误),unwind-protect 并 不保证 会执行剩下的清理代码。
如果某个 cleanup-forms 执行失败可能导致问题,可以在该表达式外层再用一个 unwind-protect 对其进行保护。
例如,下面我们创建一个不可见的缓冲区用于临时操作,并确保在结束前将其杀死:
(let ((buffer (get-buffer-create " *temp*")))
(with-current-buffer buffer
(unwind-protect
body-form
(kill-buffer buffer))))
你可能会觉得,我们完全可以写成 (kill-buffer (current-buffer)),从而省去变量 buffer。但上面这种写法更安全,可以避免 body-form 在切换到其他缓冲区后发生错误的情况!(另一种方案是在 body-form 外层使用 save-current-buffer,确保临时缓冲区能重新成为当前缓冲区,以便正常关闭。)
Emacs 提供了一个名为 with-temp-buffer 的标准宏,它展开后的代码大致就和上面展示的一样(see Current Buffer)。本手册中定义的多个宏都以这种方式使用了 unwind-protect。
下面是一个来自某 FTP 包的真实示例。它会创建一个进程(see Processes),尝试与远程机器建立连接。由于 ftp-login 函数很容易遇到各种编写者无法预料的问题,因此用一个特殊形式对其加以保护,确保在出错时能删除该进程。否则,Emacs 中可能会堆积大量无用的子进程。
(let ((win nil))
(unwind-protect
(progn
(setq process (ftp-setup-buffer host file))
(if (setq win (ftp-login process host user password))
(message "Logged in")
(error "Ftp login failed")))
(or win (and process (delete-process process)))))
这个示例存在一个小 bug:如果用户按下 C-g 退出,且退出恰好发生在函数 ftp-setup-buffer 返回之后、变量 process 赋值之前,那么该进程将不会被销毁。修复这个 bug 没有简单的办法,但至少这种情况发生的概率极低。
有时你希望只在满足特定条件时才编译某段代码。在维护 Emacs 扩展包时这种需求尤为常见:为了让扩展包兼容旧版 Emacs,你可能需要使用某些在当前 Emacs 版本中已被标记为废弃的函数或变量。
你可以在运行时使用条件表达式来选择新版或旧版代码,但这样做往往会产生关于废弃函数 / 变量的烦人警告。针对这类场景,宏 static-if 就非常实用。它的用法模仿了特殊形式 if(see 条件判断)。
如果要在旧版 Emacs 中使用该功能,可以将 static-if 的源码从 Emacs 源文件 lisp/subr.el 复制到你的扩展包中。
在宏展开阶段测试 condition。如果其值为非 nil,则将宏展开为 then-form;否则将宏展开为被 progn 包裹的 else-forms。else-forms 可以为空。
下面是来自 CC Mode 的一个使用示例,它用于避免在新版 Emacs 中编译 defadvice 结构:
(static-if (boundp 'comment-line-break-function)
(progn)
(defvar c-inside-line-break-advice nil)
(defadvice indent-new-comment-line (around c-line-break-advice
activate preactivate)
"Call `c-indent-new-comment-line' if in CC Mode."
(if (or c-inside-line-break-advice
(not c-buffer-is-cc-mode))
ad-do-it
(let ((c-inside-line-break-advice t))
(c-indent-new-comment-line (ad-get-arg 0))))))
变量(variable) 是程序中用来表示一个值的名称。在 Lisp 中,每个变量都由一个 Lisp 符号表示(see 符号)。变量名就是符号的名称,而变量的值则存储在该符号的值单元(value cell)中 10。See 符号的组成。在 Emacs Lisp 中,一个符号作为变量使用,与其作为函数名使用是相互独立的。
如本手册前面所述,Lisp 程序首先由 Lisp 对象表示,其次才表现为文本形式。Lisp 程序的文本形式,由构成该程序的 Lisp 对象的读取语法(read syntax)决定。因此,Lisp 程序中变量的文本写法,就是使用表示该变量的符号的读取语法。
使用变量最简单的方式是 全局(globally) 使用。这意味着一个变量同一时刻只有一个值,并且该值在整个 Lisp 系统中都生效(至少当前是如此)。这个值会一直有效,直到你为它指定新的值。当新值替换旧值后,变量中就不再保留旧值的痕迹。
你可以使用 setq 为一个符号指定值。例如:
(setq x '(a b))
将变量 x 的值设为 (a b)。注意,setq 是一个特殊形式(see 特殊形式):它不对第一个参数(即变量名)求值,但会对第二个参数(即新值)求值。
一旦变量拥有了值,你就可以直接将符号本身作为表达式来引用该变量。因此,
x ⇒ (a b)
假设上文所示的 setq 表达式已执行完毕。
若你再次为同一个变量赋值,新值会覆盖掉旧值:
x
⇒ (a b)
(setq x 4)
⇒ 4
x
⇒ 4
在 Emacs Lisp 中,某些符号求值时会得到自身。这包括 nil 和 t,以及所有名称以 ‘:’ 开头的符号(这类符号称为 关键字(keywords))。这些符号不能被重新绑定,其值也不能被修改。
任何试图对 nil 或 t 进行赋值或绑定的操作,都会触发 setting-constant 错误。对于关键字(名称以 ‘:’ 开头的符号)也是如此 —— 前提是它已被存入标准的对象数组(obarray)中;但将这类符号赋值为它自身不会报错。
nil ≡ 'nil
⇒ nil
(setq nil 500) error→ Attempt to set constant symbol: nil
若 object 是一个名称以 ‘:’ 开头、且已存入标准对象数组(obarray)的符号,该函数返回 t;否则返回 nil。
这些常量与使用 defconst 特殊形式定义的常量有着本质区别(see 定义全局变量)。defconst 仅用于告知开发者「你不打算修改该变量的值」,但即便你实际修改了它,Emacs 也不会抛出错误。
出于各类实际需求,还有少量额外的符号被设为只读状态。这包括 enable-multibyte-characters、most-positive-fixnum、most-negative-fixnum 以及其他一些符号。任何试图对这些符号进行赋值或绑定的操作,同样会触发 setting-constant 错误。
全局变量的值会一直保留,直到被新值显式替换为止。有时,给变量赋予一个 局部值(local value) 会非常有用 — 这种值只在 Lisp 程序的特定范围内生效。 当变量拥有局部值时,我们称该变量被 局部绑定(locally bound) 到这个值上,并称它为 局部变量(local variable)。
例如,当一个函数被调用时,其参数变量会接收局部值,这些值就是调用该函数时传入的实际参数;这些局部绑定在函数体内部生效。再比如,let 特殊形式会为指定的变量显式建立局部绑定,这些绑定仅在 let 形式的函数体内部有效。
我们也将(概念上)保存全局值的地方称为 全局绑定(global binding)。
建立一个局部绑定会保存变量之前的值(或无值状态)。我们说,之前的值 被遮蔽(shadowed) 了。
全局值和局部值都可能被遮蔽。
如果一个局部绑定正处于生效状态,对该局部变量使用 setq 会将指定的值存储到这个局部绑定中。
当该局部绑定不再生效时,之前被遮蔽的值(或无值状态)会恢复。
一个变量同一时刻可以拥有多个局部绑定(例如在嵌套的 let 表达式中对同一个变量进行绑定)。 当前绑定(current binding) 指的是实际生效的那个局部绑定,它决定了对该变量符号求值时返回的值,也是 setq 所操作的绑定。
在大多数情况下,你可以把当前绑定理解为:最内层的局部绑定;如果不存在局部绑定,则是全局绑定。更精确地说,有一条名为 作用域规则(scoping rule) 的规则,决定了局部绑定在程序中的生效位置。 Emacs Lisp 默认的作用域规则叫做 动态作用域(dynamic scoping),它的含义很简单:程序执行到任意位置时,某个变量的当前绑定,就是最近创建且仍然存在的那个绑定。 关于动态作用域的细节,以及另一种作用域规则 —— 词法作用域(lexical scoping),see Scoping 变量绑定的作用域规则。 最近,Emacs 正越来越多地使用词法绑定,目标是最终将其设为默认规则。特别地,所有 Emacs Lisp 源文件以及 *scratch* 缓冲区都已使用词法作用域。
用于创建局部绑定的特殊形式是 let 和 let*:
这个特殊形式会根据 bindings 为一组变量建立局部绑定,然后按文本顺序执行所有的 forms。它的返回值是 forms 中最后一个表达式的值。由 let 创建的局部绑定只在 forms 主体内部生效。
每个 bindings 元素有两种形式:(i) a 一个符号,此时该符号会被局部绑定到 nil;(ii) a 形如 (symbol value-form) 的列表,此时 symbol 会被局部绑定到 value-form 的求值结果。如果省略 value-form,则使用 nil。
bindings 里的所有 value-form,都会在对任何符号进行绑定 之前 按顺序求值。举个例子:z 会被绑定到 y 的旧值 2,而不是 y 的新值 1。
(setq y 2)
⇒ 2
(let ((y 1)
(z y))
(list y z))
⇒ (1 2)
另一方面, 绑定 的执行顺序并未明确规定:在下面的示例中,最终输出的结果可能是 1,也可能是 2。
(let ((x 1)
(x 2))
(print x))
因此,避免在同一个 let 形式中对同一个变量进行多次绑定。
该特殊形式与 let 类似,但它会在计算完一个变量的局部值后立即绑定该变量,再去计算下一个变量的局部值。因此,bindings 中的表达式可以引用在这个 let* 形式中前面已绑定的符号。
请将下面这个示例与前文 let 的示例对比查看。
(setq y 2)
⇒ 2
(let* ((y 1)
(z y)) ; Use the just-established value of y.
(list y z))
⇒ (1 1)
简单来说,上一个例子中 let* 对 x 和 y 的绑定,等价于使用嵌套的 let 绑定:
(let ((y 1))
(let ((z y))
(list y z)))
这个特殊形式与 let* 类似,但它会先绑定所有变量,再计算任何局部值。然后再将计算好的值赋给这些已被局部绑定的变量。这一形式只在词法绑定生效时有用,适用于你需要创建闭包,且该闭包需要引用那些在使用 let* 时尚未生效的绑定的场景。
例如,下面是一个运行一次后就将自身从钩子中移除的闭包:
(letrec ((hookfun (lambda ()
(message "Run once")
(remove-hook 'post-command-hook hookfun))))
(add-hook 'post-command-hook hookfun))
该特殊形式与 let 类似,但它会对所有变量进行动态绑定。这一用法很少见 —— 通常你希望对普通变量使用词法绑定,对特殊变量(即用 defvar 定义的变量)使用动态绑定,而这正是 let 的默认行为。
dlet 适用于与旧代码交互的场景:这些代码假定某些变量是动态绑定的(see 动态绑定),但又不方便用 defvar 去定义这些变量。dlet 会临时将被绑定的变量设为特殊变量,执行表达式,然后再把这些变量恢复为非特殊变量。
该特殊形式是受 Scheme 语言启发设计的循环结构。它与 let 类似:会为 bindings 中的变量建立绑定,然后对 body 进行求值。但除此之外,named-let 还会将 name 绑定到一个局部函数上 —— 这个函数的形参是 bindings 中的变量,函数体则是 body。这使得 body 可以通过调用 name 实现递归调用自身,调用 name 时传入的参数会作为递归调用中被绑定变量的新值。
以下是一个对数字列表求和的循环示例:
(named-let sum ((numbers '(1 2 3 4))
(running-sum 0))
(if numbers
(sum (cdr numbers) (+ running-sum (car numbers)))
running-sum))
⇒ 10
在 body 中 尾部位置(tail positions) 发生的对 name 的递归调用,会被优化为 尾部调用(tail calls)。这意味着,无论递归深度如何,它们都不会消耗额外的栈空间。此类递归调用实际上会带着变量的新值,跳转到循环的起始处重新执行。
一个函数调用处于尾部位置,是指它是整个执行过程中最后一步操作,且其返回值就是 body 的返回值。上文对 sum 的递归调用就是如此。
named-let 仅在启用词法绑定时可用。See 词法绑定。
下面是创建局部绑定的其他所有功能的完整列表:
变量还可以拥有缓冲区局部绑定(see 缓冲区局部变量);少数变量拥有终端局部绑定(see Multiple Terminals)。 这类绑定在行为上与普通局部绑定有些相似,但它们的局部化效果取决于你在 Emacs 中的当前位置。
如果一个符号的值单元(value cell)未被赋值,我们就称这个变量是空(void)的(see 符号的组成)。
在 Emacs Lisp 默认的动态作用域规则下(see Scoping 变量绑定的作用域规则),值单元存放的是变量当前的值(局部值或全局值)。注意:值单元未被赋值, 不等于 值单元里是 nil。符号 nil 本身是一个 Lisp 对象,它可以像其他对象一样成为变量的值,它仍然是一个有效值。
如果一个变量为空,那么对它进行求值时会触发 void-variable 错误,而不是返回某个值。
在可选的词法作用域规则下,值单元仅保存变量的全局值 — 即所有词法绑定结构之外的值。当变量被词法绑定时,其局部值由词法环境决定;因此,即使符号的值单元未被赋值,变量也可以拥有局部值。
该函数会清空 symbol 的值单元(value cell),使对应的变量变为空(void)状态。函数的返回值是 symbol。
若 symbol 存在动态局部绑定,makunbound 会将当前绑定置为空;且这种空状态仅在该局部绑定生效期间有效。当该局部绑定失效后,之前被遮蔽的局部绑定或全局绑定会重新生效;此时变量将不再为空,除非重新生效的绑定本身也是空的。
以下是一些示例(假设动态绑定规则已生效):
(setq x 1) ; Put a value in the global binding. ⇒ 1 (let ((x 2)) ; Locally bind it. (makunbound 'x) ; Void the local binding. x) error→ Symbol's value as variable is void: x
x ; The global binding is unchanged. ⇒ 1 (let ((x 2)) ; Locally bind it. (let ((x 3)) ; And again. (makunbound 'x) ; Void the innermost-local binding. x)) ; And refer: it’s void. error→ Symbol's value as variable is void: x
(let ((x 2))
(let ((x 3))
(makunbound 'x)) ; Void inner binding, then remove it.
x) ; Now outer let binding is visible.
⇒ 2
如果变量 variable(一个符号)不是空(void)的,该函数返回 t;如果变量为空,则返回 nil。
以下是一些示例(假设当前使用动态绑定):
(boundp 'abracadabra) ; Starts out void.
⇒ nil
(let ((abracadabra 5)) ; Locally bind it.
(boundp 'abracadabra))
⇒ t
(boundp 'abracadabra) ; Still globally void.
⇒ nil
(setq abracadabra 5) ; Make it globally nonvoid.
⇒ 5
(boundp 'abracadabra)
⇒ t
变量定义(variable definition) 是一种语法结构,用于声明你打算将一个符号用作全局变量。它使用特殊形式 defvar 或 defconst,这两者的说明见下文。
变量定义有三个作用:第一,它告诉阅读代码的人,这个符号 被设计 以某种方式(作为变量)使用;第二,它将这一信息告知 Lisp 系统,并可选择性地提供初始值与文档字符串;第三,它为诸如 etags 之类的编程工具提供信息,使这些工具能够找到该变量的定义位置。
defconst 与 defvar 的区别主要在于意图,用于告诉阅读代码的人该变量的值是否应该被修改。Emacs Lisp 实际上并不会阻止你修改由 defconst 定义的变量。两者一个明显的区别是:defconst 会无条件初始化变量,而 defvar 只在变量原本为空(void)时才进行初始化。
若要定义一个可自定义变量,你应当使用 defcustom(它会在内部调用 defvar)。See 定义自定义变量。
该特殊形式将 symbol 定义为变量,并可选择性地对其进行初始化和文档注释。注意,它不会对 symbol 进行求值;待定义的符号需显式出现在 defvar 形式中。defvar 还会将 symbol 标记为 特殊(special),这意味着该符号的绑定应始终为动态绑定(see Scoping 变量绑定的作用域规则)。
若指定了 value,且 symbol 处于空(void)状态(即无动态绑定值;see 变量为空的情况),则 defvar 会对 value 求值,并将求值结果赋值给 symbol 以完成初始化。但如果 symbol 非空,defvar 不会对 value 求值,且保留 symbol 的原有值不变。若省略 value,则 defvar 在任何情况下都不会改变 symbol 的值。
需注意,只要指定了 value(即便值为 nil),该变量就会被永久标记为特殊变量;而若省略 value,defvar 仅会将该变量局部标记为特殊变量(即:在当前词法作用域内,或若 defvar 出现在顶层,则在当前文件内)。这一特性可用于抑制字节编译警告,详见 编译器错误。
若 symbol 在当前缓冲区中存在缓冲区局部绑定,且此时指定了 value,则 defvar 会修改 symbol 的默认值(该值与缓冲区无关),而非修改其缓冲区局部绑定。仅当默认值为空时,它才会设置该默认值。See 缓冲区局部变量。
若 symbol 已被 let 绑定(例如 defvar 形式出现在 let 形式内部),则 defvar 会设置 symbol 的顶层默认值,行为与 set-default-toplevel-value 类似。该 let 绑定会一直生效,直到其所属的绑定结构执行完毕。See Scoping 变量绑定的作用域规则。
在 Emacs Lisp 模式下,当你使用 C-M-x(对应函数 eval-defun)或 C-x C-e(对应函数 eval-last-sexp)对顶层的 defvar 形式求值时,这两个命令有一个特殊机制:它们会无条件地设置该变量的值,而不会先检查变量是否为空(void)。
若提供了 doc-string 参数,该参数会为变量指定文档字符串(文档字符串会存储在符号的 variable-documentation 属性中)。See 文档。
以下是一些示例。这个形式定义了 foo,但并未对其进行初始化:
(defvar foo)
⇒ foo
本例将 bar 的值初始化为 23,并为其提供了文档字符串:
(defvar bar 23
"The normal weight of a bar.")
⇒ bar
defvar 形式的返回值是 symbol,但它通常用在文件的顶层位置,此时其返回值并不重要。
若想查看更详细的「无值使用 defvar」示例,请参见 Local defvar example。
该特殊形式将 symbol 定义为变量并对其初始化。它告知阅读代码的人:symbol 拥有在此处定义的标准全局值,用户或其他程序不应该修改它。注意:symbol 不会被求值;要定义的符号必须显式写在 defconst 中。
与 defvar 一样,defconst 会将该变量标记为特殊(special),表示它始终使用动态绑定(see Scoping 变量绑定的作用域规则)。此外,它还会将变量标记为风险变量(risky)(see 文件局部变量)。
defconst 总会对 value 求值,并将结果设为 symbol 的值。如果 symbol 在当前缓冲区中有缓冲区局部绑定,defconst 只会设置默认值,而不是缓冲区局部值。(但你不应该为用 defconst 定义的符号建立缓冲区局部绑定。)
defconst 的一个使用例子是 Emacs 里对 float-pi 的定义 — 数学常量 \(pi\),任何人都不应该修改它(尽管印第安纳州议会曾试图这么做)。不过,正如后一段代码所展示的,defconst 只起到提示作用,并非强制不可修改。
(defconst float-pi 3.141592653589793 "The value of Pi.")
⇒ float-pi
(setq float-pi 3)
⇒ float-pi
float-pi
⇒ 3
当你定义的值为函数或函数列表的变量时,应分别使用以 ‘-function’ 或 ‘-functions’ 结尾的名称。
还有一些其他的变量命名规范,完整列表如下:
该变量是普通钩子(hook)(see 钩子)。
变量的值是一个函数。
变量的值是一个函数列表。
变量的值是一个形式(表达式)。
变量的值是一个形式列表(表达式列表)。
值是一个谓词 — 即单参数函数,执行成功返回非 nil,失败返回 nil。
值的意义仅在于是否为 nil。
由于这类变量后续往往会被扩展使用更多取值,因此不强烈推荐该命名规范。
值是一个程序名。
值是一条完整的 Shell 命令。
值用于指定命令的选项参数。
该变量为内部使用,定义在文件 prefix.el 中。 (2018 年之前贡献的 Emacs 代码可能遵循其他已逐步淘汰的规范。)
该变量供内部使用,且是在 C 代码中定义的。 (2018 年之前贡献的 Emacs 代码可能遵循其他规范,这些规范正在逐步淘汰。)
定义变量时,务必考虑是否应将其标记为安全(safe)或风险(risky),详见 文件局部变量。
当定义并初始化一个持有复杂值的变量时(例如主模式对应的语法表),最好将值的整个计算逻辑都写进 defvar 中,示例如下:
(defvar my-major-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?# "<" table)
...
table)
docstring)
这种方法有多个优点。首先,如果用户在加载文件的过程中退出,该变量要么仍未初始化,要么已正确完成初始化,绝不会处于中间状态。若变量仍未初始化,重新加载文件即可完成正确的初始化。其次,变量初始化完成后重新加载文件,其值不会被改变 —— 这一点在用户已修改过变量值的情况下尤为重要。第三,使用 C-M-x 对 defvar 形式求值时,会对该变量进行完全的重新初始化。
引用变量的常规方式是书写其对应的符号名称。See 符号形式。
偶尔你可能需要引用一个仅在运行时才能确定的变量,这种情况下无法在程序代码中直接指定变量名,此时可以使用 symbol-value 函数来获取其值。
该函数返回存储在 symbol 值域(value cell)中的值,变量当前的(动态)值就存储在这里。如果该变量没有局部绑定,返回的就是其全局值;如果变量为空(void),则会触发 void-variable 错误。
如果变量是词法绑定的,那么 symbol-value 返回的值不一定等于该变量的词法值。词法值由词法环境决定,而非由符号的值域(value cell)决定。See Scoping 变量绑定的作用域规则。
(setq abracadabra 5)
⇒ 5
(setq foo 9)
⇒ 9
;; Here the symbol abracadabra
;; is the symbol whose value is examined.
(let ((abracadabra 'foo))
(symbol-value 'abracadabra))
⇒ foo
;; Here, the value ofabracadabra, ;; which isfoo, ;; is the symbol whose value is examined. (let ((abracadabra 'foo)) (symbol-value abracadabra)) ⇒ 9
(symbol-value 'abracadabra)
⇒ 5
修改变量值的常规方式是使用特殊形式 setq。如果你需要在运行时动态计算要操作的变量,则使用函数 set。
该特殊形式是最常用的变量赋值方式。每个 symbol 会被赋予一个新值,该值为对应 form 表达式的求值结果。符号的当前绑定会被修改。
setq 不会对 symbol 求值,而是直接设置你写出的符号。我们称这个参数是 自动引用(automatically quoted) 的。setq 中的 ‘q’ 代表 “quoted(引用)”。
setq 形式的值,等于最后一个 form 表达式的值。
(setq x (1+ 2))
⇒ 3
x ; x now has a global value.
⇒ 3
(let ((x 5))
(setq x 6) ; The local binding of x is set.
x)
⇒ 6
x ; The global value is unchanged.
⇒ 3
需要注意的是,第一个 form 会先被求值,随后第一个 symbol 被赋值;接着第二个 form 被求值,然后第二个 symbol 被赋值,依此类推:
(setq x 10 ; Notice thatxis set before y (1+ x)) ; the value ofyis computed. ⇒ 11
该函数会将 value 存入 symbol 的值单元(value cell)中。由于它是一个函数而非特殊形式,程序会对 symbol 对应的表达式求值,以确定要赋值的符号。函数的返回值为 value。
当动态变量绑定生效时(默认行为),除了「set 会对其 symbol 参数求值,而 setq 不会」这一点外,set 与 setq 的作用效果完全相同。但当变量为词法绑定时,set 会修改该变量的 动态(dynamic) 值,而 setq 会修改其当前的(词法)值。See Scoping 变量绑定的作用域规则。
(set one 1) error→ Symbol's value as variable is void: one
(set 'one 1)
⇒ 1
(set 'two 'one)
⇒ one
(set two 2) ; two evaluates to symbol one.
⇒ 2
one ; So it isonethat was set. ⇒ 2 (let ((one 1)) ; This binding ofoneis set, (set 'one 3) ; not the global value. one) ⇒ 3
one
⇒ 2
若 symbol 实际上并非符号,则会触发 wrong-type-argument 错误。
(set '(x y) 'z) error→ Wrong type argument: symbolp, (x y)
该宏的作用与 setq 类似(见上文),但专用于用户可配置项(user options)。此宏会调用自定义机制(Customize machinery)来设置变量(可指定多个)(see 定义自定义变量)。值得注意的是,setopt 会执行与该变量关联的设置函数(setter function)。例如,若你编写了如下代码:
(defcustom my-var 1
"My var."
:type 'number
:set (lambda (var val)
(set-default var val)
(message "We set %s to %s" var val)))
那么下面的代码除了会把 my-var 设置为 ‘2’ 之外,还会输出一条提示信息:
(setopt my-var 2)
setopt 还会检查该值是否对这个用户可配置项有效。例如,若使用 setopt 将一个定义为 number 类型的用户可配置项设置为字符串,会触发错误。
与 defcustom 及相关的自定义命令(如 customize-variable)不同,setopt 适用于非交互式场景,尤其常用于用户的初始化文件(init file)中。因此,它不会记录变量的标准值、保存值和用户设定值,也不会将该变量标记为可保存到自定义文件(custom file)的候选项。
setopt 宏也可用于普通的非用户可配置项变量,但效率远低于 setq。该宏的主要使用场景是在用户的初始化文件中设置用户可配置项。
有时在变量的值发生改变时执行某些操作会很有用。变量监视点(variable watchpoint) 机制就提供了这样的功能。该特性的常见用途包括:让显示内容与变量设置保持同步,以及调用调试器追踪变量的意外修改(see 修改变量时进入调试器)。
以下函数可用于管理和查询变量的监视函数。
该函数会设定:每当 symbol 被修改时,就调用 watch-function。通过变量别名进行的修改也会触发同样效果(see 变量别名)。
watch-function 会在即将修改 symbol 的值之前被调用,并传入 4 个参数:symbol、newval、operation 和 where。
symbol 是正在被修改的变量。newval 是变量即将被设置成的新值。(旧值此时仍然可以通过 symbol 本身获取,因为它还没有被更新为 newval。)
operation 是一个符号,表示修改的类型,为下列之一:set、let、unlet、makunbound 或 defvaralias。
如果修改的是变量的缓冲区局部值,where 为对应的缓冲区;否则为 nil。
该函数会将 watch-function 从 symbol 的监视函数列表中移除。
该函数返回 symbol 已激活的监视函数列表。
有几种方式可以修改变量(或至少看起来被修改),但不会触发监视点。
由于监视点是附加在符号上的,因此对变量内部包含的对象进行修改(例如通过列表修改函数,see 修改已有列表结构)不会被该机制捕获。
此外,C 代码可以直接修改变量的值,绕过监视点机制。
该功能的一个小局限同样源于它基于符号:只有动态作用域的变量可以被监视。这通常不会带来太大问题,因为对词法变量的修改可以很容易地通过检查变量作用域内的代码来发现(而动态变量则可能被任意代码修改,see Scoping 变量绑定的作用域规则)。
当你为变量创建局部绑定时,该绑定仅在程序的有限区域内生效(see 局部变量)。本节将精确说明其含义。
每个局部绑定都有确定的 作用域(scope) 和 存在期(extent)。作用域(scope) 指的是该绑定在源代码文本中 哪些 位置可以被访问。存在期(Extent) 指的是在程序执行过程中,该绑定在哪些时刻存在。
由于历史原因,Emacs Lisp 存在两种方言,通过缓冲区局部变量 lexical-binding 进行选择。在现代 Emacs Lisp 方言中,局部绑定默认是词法绑定。
词法绑定(lexical binding) 具有 词法作用域(lexical scope),意味着对该变量的任何引用都必须在文本上位于绑定结构内部11。它同时具有 无限存在期(indefinite extent),意味着在某些情况下,通过名为 闭包(closures) 的对象,即使绑定结构已执行完毕,该绑定仍然可以继续存在。词法作用域通常也被称为 静态作用域(static scoping)。
局部绑定也可以是动态绑定:在旧版 Emacs Lisp 方言中一律如此,在现代方言中则作为可选方式。动态绑定(dynamic binding) 具有 动态作用域(dynamic scope),意味着程序的任何部分都有可能访问该变量绑定。它同时具有 动态存在期(dynamic extent),意味着该绑定仅在绑定结构(如 let 表达式的体)正在执行时才有效。
旧的仅支持动态绑定的 Emacs Lisp 方言,在缺少方言声明的 Lisp 文件中被加载或求值时,仍然是默认方言。最终,现代方言将会被设为默认。 所有 Lisp 文件都应当声明所使用的方言,以确保它们在未来仍能正常运行。
下面的小节将更详细地介绍词法绑定和动态绑定,以及如何在 Emacs Lisp 程序中启用词法绑定。
词法绑定仅在现代版 Emacs Lisp 方言中可用。(See 选择 Lisp 方言.) 使用词法绑定的变量具有 词法作用域(lexical scope),意思是:对该变量的任何引用,在文本上都必须位于该绑定结构内部。下面是一个示例:
(let ((x 1)) ;xis lexically bound. (+ x 3)) ⇒ 4 (defun getx () x) ;xis used free in this function. (let ((x 1)) ;xis lexically bound. (getx)) error→ Symbol's value as variable is void: x
在此示例中,变量 x 没有全局值。当它在 let 表达式内被词法绑定时,仅能在该 let 表达式的文本范围内使用。但从 let 表达式中调用 getx 函数时,却 无法 在该函数内部使用这个变量 — 因为 getx 的函数定义出现在 let 表达式本身的外部。
词法绑定的工作机制如下:每个绑定结构都会定义一个 词法环境(lexical environment),该环境会指定在这个结构内被绑定的变量及其局部值。当 Lisp 求值器需要获取变量的当前值时,会首先在词法环境中查找;如果变量未在词法环境中定义,则会去符号的值单元(value cell)中查找(动态值即存储于此)。
词法绑定具有无限存在期。即便绑定结构执行完毕,其词法环境仍可通过名为 闭包(closures) 的 Lisp 对象 “留存(kept around)” 下来。当你在启用词法绑定的情况下定义命名函数或匿名函数时,就会创建闭包。See 闭包。
当闭包作为函数被调用时,其定义内的所有词法变量引用都会使用留存的词法环境。以下是一个示例:
(defvar my-ticker nil) ; We will use this dynamically bound ; variable to store a closure. (let ((x 0)) ;xis lexically bound. (setq my-ticker (lambda () (setq x (1+ x))))) ⇒ #f(lambda () [(x 0)] (setq x (1+ x))) (funcall my-ticker) ⇒ 1 (funcall my-ticker) ⇒ 2 (funcall my-ticker) ⇒ 3 x ; Note thatxhas no global value. error→ Symbol's value as variable is void: x
在这里,let 绑定定义了一个词法环境,其中变量 x 被局部绑定为 0。在这个绑定结构内部,我们定义了一个 lambda 表达式,它将 x 加 1 并返回递增后的值。这个 lambda 表达式会自动变成闭包,其中的词法环境即使在 let 绑定结构退出后依然会继续存在。每次我们对这个闭包求值时,它都会使用那个词法环境里的 x 绑定,并对 x 进行加 1。
注意:与动态变量直接绑定到符号对象本身不同,词法变量与符号之间的关系只存在于解释器(或编译器)内部。因此,接收符号作为参数的函数(如 symbol-value、boundp 和 set)只能获取或修改变量的动态绑定(即符号的值单元里的内容)。
还要注意:变量可以被声明为 special,此时即使是新的绑定(例如 let 绑定)也会使用动态绑定。根据变量声明方式的不同,它可以是全局特殊、单个文件内特殊,或文件中某一段代码内特殊。See 动态绑定。
在现代 Lisp 方言中,特殊变量(见下文)的局部变量绑定是动态的;而在旧版 Lisp 方言中,所有变量的绑定都是动态的。(See 选择 Lisp 方言。) 动态变量绑定有其适用场景,但总体来说比词法绑定更容易出错、效率更低,并且编译器也更难发现使用动态绑定的代码中的错误。
当一个变量是动态绑定时,在 Lisp 程序执行的任意时刻,它的当前绑定就是该符号最近创建的动态局部绑定;如果不存在这样的局部绑定,则使用全局绑定。
动态绑定具有动态作用域和动态存在期,如下例所示:
(defvar x -99) ;xreceives an initial value of −99. (defun getx () x) ;xis used free in this function. (let ((x 1)) ;xis dynamically bound. (getx)) ⇒ 1 ;; After theletform finishes,xreverts to its ;; previous value, which is −99. (getx) ⇒ -99
函数 getx 引用了 x。这是一种自由引用(free reference)—— 也就是说,在 defun 这个绑定结构内部,并没有为 x 建立任何绑定。当我们在一个将 x(以动态方式)绑定的 let 表达式内部调用 getx 时,它会获取到这个局部值(即 1);但当我们在 let 表达式外部调用 getx 时,它会获取到全局值(即 −99)。
再看另一个示例,该示例展示了如何使用 setq 设置动态绑定的变量:
(defvar x -99) ;xreceives an initial value of −99. (defun addx () (setq x (1+ x))) ; Add 1 toxand return its new value. (let ((x 1)) (addx) (addx)) ⇒ 3 ; The twoaddxcalls add toxtwice. ;; After theletform finishes,xreverts to its ;; previous value, which is −99. (addx) ⇒ -98
即使启用了词法绑定,某些变量仍然会使用动态绑定。这些变量被称为 特殊变量(special variables)。所有通过 defvar、defcustom 或 defconst 定义的变量都是特殊变量(see 定义全局变量)。其余所有变量则采用词法绑定。
使用不带初始值的 defvar,可以只在单个文件内,或文件的某一部分代码中将变量设为动态绑定,而在其他地方仍然使用词法绑定。例如:
(let (_) (defvar x) ; Let-bindings ofxwill be dynamic within this let. (let ((x -99)) ; This is a dynamic binding ofx. (defun get-dynamic-x () x))) (let ((x 'lexical)) ; This is a lexical binding ofx. (defun get-lexical-x () x)) (let (_) (defvar x) (let ((x 'dynamic)) (list (get-lexical-x) (get-dynamic-x)))) ⇒ (lexical dynamic)
该函数会检查 symbol 是否为特殊变量:如果是(即该变量通过 defvar、defcustom 或 defconst 完成了变量定义),则返回非 nil 值;否则返回 nil。
需要注意的是,由于这是一个函数,它仅会对永久特殊的变量返回非 nil 值,而对于仅在当前词法作用域内特殊的变量,不会返回非 nil 值。
不支持将特殊变量用作函数的形式参数。
Emacs Lisp 以一种简单的方式实现动态绑定:每个符号都有一个值单元(value cell),用于存储该符号当前的动态值(或标记无值状态)(See 符号的组成)。当为一个符号创建动态局部绑定时,Emacs 会先将值单元中的原有内容(或无值状态)记录到栈中,再把新的局部值存入值单元;当绑定结构执行完毕后,Emacs 会将栈中保存的旧值弹出,并重新写入值单元。
动态绑定是一项强大的特性,因为它允许程序引用不在自身局部文本作用域内定义的变量。但是,如果不加节制地使用,也会让程序难以理解。
首先,要谨慎选择变量名,避免命名冲突(see Emacs Lisp Coding Conventions)。
defvar 表达式将其声明为特殊变量,并且永远只在它已被绑定时才对其赋值。这样一来,任何在未绑定时引用该变量的操作都会触发 void-variable 错误。
defvar、defconst(see 定义全局变量)或 defcustom(see 定义自定义变量)来定义变量。通常,定义应放在 Emacs Lisp 文件的顶层。定义中应尽可能包含文档字符串,说明变量的含义与用途。
这样你就可以在程序的任意位置对该变量进行绑定,并且能确切预知绑定的效果。无论在何处遇到该变量,都可以很方便地回溯到它的定义,例如通过 C-h v 命令(前提是变量定义已被加载到 Emacs 中)。See Name Help in The GNU Emacs Manual。
例如,对于像 case-fold-search 这类可自定义变量,使用局部绑定是很常见的做法:
(defun search-for-abc ()
"Search for the string \"abc\", ignoring case differences."
(let ((case-fold-search t))
(re-search-forward "abc")))
在加载 Emacs Lisp 文件或对 Lisp 缓冲区进行求值时,Lisp 方言由缓冲区局部变量 lexical-binding 决定。
如果这个缓冲区局部变量的值为非 nil,Emacs Lisp 文件和缓冲区将使用现代 Lisp 方言进行解析,该方言默认使用词法绑定而非动态绑定。如果为 nil,则使用旧方言,即对所有局部变量都采用动态绑定。
该变量通常作为文件局部变量为整个 Emacs Lisp 文件设置(see 文件局部变量)。注意:与其他此类变量不同,该变量必须写在文件的第一行。
在实际使用中,选择方言意味着 Emacs Lisp 文件的第一行通常形如:
;;; ... -*- lexical-binding: t -*-
for the modern lexical-binding dialect, and
;;; ... -*- lexical-binding: nil -*-
上述写法适用于仅支持动态绑定的旧方言。若未声明方言类型,默认会使用旧方言,但这一行为可能在未来版本中变更。如果未声明方言类型,编译器会发出警告。
当通过 eval 调用直接求值 Emacs Lisp 代码时,若传给 eval 的 lexical 参数为非 nil 值,则会启用词法绑定。See 求值。
词法绑定同样会在以下场景中启用:
Lisp Interaction 模式和 IELM 模式(分别用于 *scratch* 和 *ielm* 缓冲区);
通过 M-:(对应 eval-expression 函数)求值表达式时;
处理 Emacs 的 --eval 命令行选项(see Action Arguments in The GNU Emacs Manual)和 emacsclient 的 --eval 命令行选项时(see emacsclient Options in The GNU Emacs Manual)。
将 Emacs Lisp 程序迁移为词法绑定的过程很简单:
首先,在 Emacs Lisp 源文件的头部行中,添加文件局部变量设置,将 lexical-binding 设为 t(see 文件局部变量);
其次,检查程序中所有需要动态绑定的变量:确保这些变量都有对应的变量定义,避免被意外地词法绑定。
判断哪些变量需要定义的一种简单方法,是对源文件进行字节编译。See 字节编译。如果一个非特殊变量在 let 表达式之外被使用,字节编译器会警告:对自由变量的引用或赋值。如果一个非特殊变量在 let 表达式中被绑定但未被使用,字节编译器会警告:存在未使用的词法变量。如果你将特殊变量用作函数参数,字节编译器同样会发出警告。
出现对自由变量的引用或赋值这类警告,通常明确说明:该变量应当被标记为动态作用域,因此你需要在变量第一次使用之前,添加合适的 defvar 声明。
未使用变量的警告,可能是一个很好的提示:该变量本意是要使用动态作用域(因为它确实在其他函数中被使用),但也可能只是说明:该变量确实完全没用,可以直接删除。
所以你需要判断属于哪种情况,然后据此要么添加 defvar,要么彻底删除该变量。如果无法或不希望删除(通常因为它是形式参数,而你不能或不想修改所有调用处),也可以在变量名前加一个下划线,用来告诉编译器:这个变量是故意不使用的。
警告: 这是一项实验性特性,可能会在未经预先通知的情况下发生变更或被移除。
字节编译器还可以对在其他 Emacs Lisp 文件中被声明为特殊变量的词法变量发出警告,这种情况通常意味着缺少了 defvar 声明。这项实用但较为专业的检查需要三个步骤:
EMACS_GENERATE_DYNVARS 设置为非空字符串,然后对所有你关心其特殊变量声明的文件进行字节编译。这些文件通常是同一个软件包、相关软件包或 Emacs 子系统中的所有文件。此过程会为每个被编译的 Emacs Lisp 文件生成一个以 .dynvars 结尾的文件。
EMACS_DYNVARS_FILE设置为步骤 2 中生成的合并文件的文件名。
下面是一个示例,演示具体如何操作,假设使用 Unix Shell 和 make 工具进行字节编译:
$ rm *.elc # force recompilation $ EMACS_GENERATE_DYNVARS=1 make # generate .dynvars $ cat *.dynvars > ~/my-dynvars # combine .dynvars $ rm *.elc # force recompilation $ EMACS_DYNVARS_FILE=~/my-dynvars make # perform checks
全局变量和局部变量绑定在大多数编程语言中都以各种形式存在。而 Emacs 还额外支持一些特殊的变量绑定方式,例如 缓冲区局部(buffer‑local) 绑定,它只在单个缓冲区中生效。 让同一个变量在不同缓冲区中拥有不同的值,是一种重要的定制手段。(变量也可以拥有对每个终端都局部的绑定。See Multiple Terminals。)
缓冲区局部变量拥有与特定缓冲区关联的缓冲区局部绑定。当该缓冲区成为当前缓冲区时,该绑定生效;否则不生效。如果你在缓冲区局部绑定生效时修改变量,新值只会存入该绑定,其他绑定保持不变。也就是说,修改只在你执行操作的这个缓冲区中可见。
变量不与任何特定缓冲区关联的普通绑定,称为 默认绑定(default binding)。大多数情况下,默认绑定就是全局绑定。
一个变量可以在部分缓冲区中拥有缓冲区局部绑定,在其他缓冲区中则没有。所有没有为该变量建立自身绑定的缓冲区(包括所有新建的缓冲区),都会共享默认绑定。如果你在一个没有为该变量建立缓冲区局部绑定的缓冲区中修改它,修改的是默认绑定,因此新值会在所有使用默认绑定的缓冲区中生效。
缓冲区局部绑定最常见的用途,是让主模式修改控制命令行为的相关变量。例如,C 模式和 Lisp 模式都会修改变量 paragraph-start,用来规定只有空行才能分隔段落。它们的实现方式是:在切换到 C 模式或 Lisp 模式的缓冲区中,将该变量设为缓冲区局部变量,然后为该模式设置新值。See 主模式。
创建缓冲区局部绑定的常规方式是使用 make-local-variable 函数,这也是主模式命令最常采用的方式。该操作仅作用于当前缓冲区;所有其他缓冲区(包括尚未创建的缓冲区)会继续共享默认值,除非显式为它们创建专属的缓冲区局部绑定。
一种功能更强的操作是调用 make-variable-buffer-local,将变量标记为 自动缓冲区局部(automatically buffer-local) 变量。你可以理解为:这会让该变量在所有缓冲区(甚至尚未创建的缓冲区)中都成为局部变量。更准确地说,其效果是:当修改变量时,如果该变量尚未成为当前缓冲区的局部变量,会自动将其设为当前缓冲区的局部变量。
所有缓冲区初始时都会像往常一样共享该变量的默认值,但对变量的赋值操作会为当前缓冲区创建缓冲区局部绑定。新值会存入这个缓冲区局部绑定中,而默认绑定保持不变。这意味着:无法通过 setq 在任何缓冲区中修改默认值;修改默认值的唯一方式是使用 setq-default。
警告: 当一个变量在一个或多个缓冲区中存在缓冲区局部绑定时,let 会对当前生效的绑定进行临时重绑定。例如:如果当前缓冲区有缓冲区局部值,let 会临时重绑定这个局部值;如果没有生效的缓冲区局部绑定,let 会重绑定默认值。
若在 let 块内切换到另一个当前缓冲区(该缓冲区中生效的是另一套绑定),你将无法再看到 let 创建的临时绑定。而如果在切换后的缓冲区中退出 let 块,你不会看到解绑操作的直观效果(尽管解绑会正常执行)。以下示例可说明这一点:
(setq foo 'g) (set-buffer "a") (make-local-variable 'foo)
(setq foo 'a) (let ((foo 'temp)) ;; foo ⇒ 'temp ; let binding in buffer ‘a’ (set-buffer "b") ;; foo ⇒ 'g ; the global value since foo is not local in ‘b’ body...)
foo ⇒ 'g ; exiting restored the local value in buffer ‘a’, ; but we don’t see that in buffer ‘b’
(set-buffer "a") ; verify the local value was restored
foo ⇒ 'a
注意,在 body 中对 foo 的引用会访问缓冲区 ‘b’ 的缓冲区局部绑定。
当文件指定了局部变量值时,在你打开该文件时,这些值会成为缓冲区局部值。See File Variables in The GNU Emacs Manual。
终端局部变量无法被设为缓冲区局部变量(see Multiple Terminals)。
该函数在当前缓冲区中为 variable(一个符号)创建缓冲区局部绑定。其他缓冲区不受影响。返回值为 variable。
variable 的缓冲区局部值初始时与其原先的值相同。如果 variable 原本未定义,则它保持未定义状态。
;; In buffer ‘b1’: (setq foo 5) ; Affects all buffers. ⇒ 5
(make-local-variable 'foo) ; Now it is local in ‘b1’.
⇒ foo
foo ; That did not change ⇒ 5 ; the value.
(setq foo 6) ; Change the value ⇒ 6 ; in ‘b1’.
foo
⇒ 6
;; In buffer ‘b2’, the value hasn’t changed.
(with-current-buffer "b2"
foo)
⇒ 5
在变量的 let 绑定范围内为该变量创建缓冲区局部绑定的做法无法保证可靠性,除非执行此操作的缓冲区在进入或退出 let 时均非当前缓冲区。这是因为 let 不会区分不同类型的绑定 —— 它仅记录该绑定对应的变量名称。
为常量或只读变量创建缓冲区局部绑定属于错误操作。See 永不改变的变量。
若该变量是终端局部变量(see Multiple Terminals),此函数会抛出错误。这类变量无法同时拥有缓冲区局部绑定。
警告: 切勿对钩子变量使用 make-local-variable。如果你在调用 add-hook 或 remove-hook 时传入 local 参数,钩子变量会在需要时自动成为缓冲区局部变量。
pairs 是一组 “变量 - 值” 配对列表。该宏会为列表中的每个变量在当前缓冲区创建缓冲区局部绑定,并为其赋予缓冲区局部值。这等效于对每个变量依次调用 make-local-variable 后再调用 setq。这些变量应为未加引号的符号。
(setq-local var1 "value1"
var2 "value2")
该函数将 variable(一个符号)标记为自动缓冲区局部变量,此后任何对它的赋值操作,都会使其在当前缓冲区中变为局部。它常与 make-local-variable 混淆,但与之不同的是:此操作无法撤销,并且会影响所有缓冲区中该变量的行为。
该特性有一个特殊之处:使用 let 或其他绑定结构对变量进行绑定,并不会为其创建缓冲区局部绑定。只有在变量没有在当前缓冲区中建立过 let 风格绑定的前提下,通过 set 或 setq 对变量赋值,才会建立缓冲区局部绑定。
如果 variable 原本没有默认值,调用此命令会为其赋予默认值 nil。如果 variable 已有默认值,则该值保持不变。后续对 variable 调用 makunbound,只会使其缓冲区局部值变为未定义,而不会影响其默认值。
返回值为 variable。
为常量或只读变量设置为缓冲区局部属于错误操作。See 永不改变的变量。
警告: 不要仅仅因为用户 可能 希望在不同缓冲区中对用户选项变量进行不同定制,就想当然地使用 make-variable-buffer-local。用户在需要时,可以自行将任意变量设为局部。将选择权交给用户会是更好的做法。
使用 make-variable-buffer-local 的场景是:必须确保任意两个缓冲区绝不会共享同一个绑定。例如,当某个变量被 Lisp 程序用于内部逻辑,且该程序依赖于「不同缓冲区中该变量拥有独立值」的特性时,使用 make-variable-buffer-local 会是最佳解决方案。
该宏将 variable 定义为一个变量,为其设置初始值 value 和文档字符串 docstring,并将其标记为自动缓冲区局部变量。这等效于先调用 defvar,再调用 make-variable-buffer-local。variable 应为未加引号的符号。
若 variable 在缓冲区 buffer(默认值为当前缓冲区)中是缓冲区局部变量,则返回 t;否则返回 nil。
若 variable 满足以下任一条件,返回 t:
在缓冲区 buffer 中拥有缓冲区局部值;
或被标记为自动缓冲区局部变量。
若不满足上述条件,则返回 nil。若 buffer 参数被省略或传入 nil,则默认使用当前缓冲区。
该函数返回缓冲区 buffer 中 variable(一个符号)的缓冲区局部绑定值。若 variable 在缓冲区 buffer 中无缓冲区局部绑定,则返回该变量的默认值(see 缓冲区局部变量的默认值)。
若满足以下任一条件,该函数返回非 nil 值:
缓冲区 buffer 中存在 variable(一个符号)的缓冲区局部绑定;
或 variable 拥有全局绑定。
该函数返回一个列表,描述缓冲区 buffer 中的所有缓冲区局部变量。(若省略 buffer 参数,则使用当前缓冲区。)通常,列表中的每个元素格式为 (sym . val):其中 sym 是缓冲区局部变量(符号),val 是其对应的缓冲区局部值。但如果某个变量在 buffer 中的缓冲区局部绑定为「未定义(void)」状态,则其在列表中仅以 sym 单个符号的形式存在。
(make-local-variable 'foobar) (makunbound 'foobar) (make-local-variable 'bind-me) (setq bind-me 69)
(setq lcl (buffer-local-variables))
;; First, built-in variables local in all buffers:
⇒ ((mark-active . nil)
(buffer-undo-list . nil)
(mode-name . "Fundamental")
...
;; Next, non-built-in buffer-local variables. ;; This one is buffer-local and void: foobar ;; This one is buffer-local and nonvoid: (bind-me . 69))
注意,向此列表中cons 单元的 CDR 部分存入新值,并 不会 改变这些变量的缓冲区局部值。
该函数删除当前缓冲区中 variable(一个符号)的缓冲区局部绑定(如果存在)。执行后,variable 的默认绑定会在此缓冲区中生效。这通常会导致 variable 的值发生变化,因为默认值通常与刚刚删除的缓冲区局部值不同。
如果你删除了一个被赋值后自动变为缓冲区局部的变量的局部绑定,这会使默认值在当前缓冲区中生效。但是,如果你再次对该变量赋值,将会重新为它创建缓冲区局部绑定。
kill-local-variable 返回 variable。
该函数是一个交互式命令,因为有时在交互使用中删除某个缓冲区局部变量是很有用的,就像交互式创建缓冲区局部变量一样有用。
该函数清除当前缓冲区的所有缓冲区局部变量绑定。执行后,该缓冲区将使用绝大多数变量的默认值。默认情况下,被标记为「永久(permanent)」的变量、以及拥有非 nil 类型 permanent-local-hook 属性的局部钩子函数(see 设置钩子)不会被清除;但如果可选参数 kill-permanent 为非 nil 值,这些变量也会被清除。
该函数还会重置缓冲区的若干其他相关信息:将局部按键映射设为 nil,将语法表设为 (standard-syntax-table) 的值,将大小写转换表设为 (standard-case-table),并将缩写表设为 fundamental-mode-abbrev-table 的值。
该函数执行的第一个操作是运行普通钩子 change-major-mode-hook(见下文)。
每个主模式命令都会先调用此函数 —— 这一操作等效于切换到基本模式(Fundamental mode),并清除上一个主模式产生的大部分效果。为确保该函数能正常工作,主模式所设置的变量不应被标记为「永久」。
kill-all-local-variables 返回 nil。
函数 kill-all-local-variables 会在执行任何其他操作之前运行这个普通钩子。这为主模式提供了一种机制:当用户切换到另一个主模式时,可通过该钩子执行特定的自定义操作。对于「缓冲区专属的次要模式」而言,该钩子也很有用 —— 若用户切换主模式,这类次要模式应被清除,可通过此钩子实现。
为达到最佳效果,应将此变量设为缓冲区局部变量:这样它在完成自身使命后便会消失,且不会干扰后续切换的主模式。See 钩子。
若某个缓冲区局部变量的名称(符号)拥有非 nil 的 permanent-local 属性,则该变量被称为 永久(permanent) 缓冲区局部变量。此类变量不受 kill-all-local-variables 影响,因此切换主模式时,其局部绑定不会被清除。永久局部变量适合存储与「文件来源」「文件保存方式」相关的数据,而非与「内容编辑方式」相关的数据。
拥有缓冲区局部绑定的变量,其全局值也被称为 默认值(default)——这是因为当当前缓冲区没有该变量的专属绑定(局部值)时,生效的就是这个默认值。
函数 default-value 和 setq-default 用于访问和修改变量的默认值,不受当前缓冲区是否存在该变量的缓冲区局部绑定影响。例如,你可以使用 setq-default 修改 paragraph-start 的默认设置(该设置会作用于绝大多数缓冲区);即便你正处于 C 模式或 Lisp 模式缓冲区(这类缓冲区通常为该变量设置了缓冲区局部值),此操作依然有效。
特殊形式 defvar 和 defconst 同样只会设置变量的默认值(如果它们确实对变量进行了赋值),而非任何缓冲区局部值。
该函数返回 symbol 的默认值。这是那些未为该变量设置专属值的缓冲区和框架(frame)所使用的值。若 symbol 并非缓冲区局部变量,则该函数等效于 symbol-value(see 访问变量值)。
函数 default-boundp 用于判断 symbol 的默认值是否为非未定义(nonvoid)状态。若 (default-boundp 'foo) 返回 nil,则调用 (default-value 'foo) 会触发错误。
default-boundp 与 default-value 的关系,等同于 boundp 与 symbol-value 的关系。
该特殊形式为每个 symbol(符号)赋予新的默认值,新值为对应 form(表达式)的求值结果。此操作不会对 symbol 进行求值,但会对 form 求值。整个 setq-default 形式的返回值为最后一个 form 的求值结果。
若某个 symbol 对当前缓冲区而言非缓冲区局部变量,且未被标记为自动缓冲区局部变量,则 setq-default 的效果与 setq 完全相同。若 symbol 是当前缓冲区的缓冲区局部变量,则此操作会修改「其他缓冲区将看到的值」(前提是这些缓冲区没有该变量的缓冲区局部值),但不会改变当前缓冲区所看到的该变量值。
;; In buffer ‘foo’:
(make-local-variable 'buffer-local)
⇒ buffer-local
(setq buffer-local 'value-in-foo)
⇒ value-in-foo
(setq-default buffer-local 'new-default)
⇒ new-default
buffer-local
⇒ value-in-foo
(default-value 'buffer-local)
⇒ new-default
;; In (the new) buffer ‘bar’:
buffer-local
⇒ new-default
(default-value 'buffer-local)
⇒ new-default
(setq buffer-local 'another-default)
⇒ another-default
(default-value 'buffer-local)
⇒ another-default
;; Back in buffer ‘foo’:
buffer-local
⇒ value-in-foo
(default-value 'buffer-local)
⇒ another-default
This function is like setq-default, except that symbol is
an ordinary evaluated argument.
(set-default (car '(a b c)) 23)
⇒ 23
(default-value 'a)
⇒ 23
变量可通过 let 绑定(see 局部变量)赋予某个值。此操作会让该变量的全局值被这个绑定遮蔽;此时 default-value 将返回该绑定中的值(而非全局值),且 set-default 会被阻止修改全局值(转而修改这个 let 绑定的值)。以下两个函数可在全局值被 let 绑定遮蔽时,依然能引用到全局值。
该函数返回 symbol 的 顶层(top-level) 默认值,即该变量在所有 let 绑定之外的取值。
(defvar variable 'global-value)
⇒ variable
(let ((variable 'let-binding))
(default-value 'variable))
⇒ let-binding
(let ((variable 'let-binding))
(default-toplevel-value 'variable))
⇒ global-value
该函数将 symbol 的顶层默认值设置为指定的 value。当你希望无视代码是否运行在 symbol 的 let 绑定上下文中,直接修改该符号的全局值时,这个函数会非常实用。
文件可以指定局部变量值;Emacs 会利用这些值,在访问该文件的缓冲区中为这些变量创建缓冲区局部绑定。关于文件局部变量的基础信息,可参考 See Local Variables in Files in The GNU Emacs Manual。本节将介绍影响文件局部变量处理逻辑的函数与变量。
若文件局部变量能够指定任意函数或 Lisp 表达式(且这些代码会在后续被调用),那么访问该文件可能会导致你的 Emacs 被恶意控制。为防范此类风险,Emacs 仅会自动设置那些「指定值被判定为安全」的文件局部变量;其余文件局部变量仅会在用户明确同意后才会被设置。
为进一步提升安全性,当 Emacs 读取文件局部变量时,会将 read-circle 临时绑定为 nil(see 输入函数)。这一操作可阻止 Lisp 读取器识别循环型和共享型 Lisp 结构(see 循环对象的读取语法)。
该变量用于控制是否处理文件局部变量。其可选值如下:
t (the default)设置所有安全变量,并针对所有不安全变量发起一次确认询问。
:safe仅设置安全变量,且不发起任何询问。
:all设置所有变量,且不发起任何询问。
nil不设置任何变量。
针对所有变量发起一次确认询问。
该变量是一个正则表达式列表。若某个文件的名称匹配此列表中的任意一项,则 Emacs 不会扫描该文件中任何形式的文件局部变量。关于使用该变量的场景示例,可参考 see Emacs 如何选择主模式。
部分局部变量设置,即便在 enable-local-variables 设为 nil 的情况下,默认仍会生效。默认情况下,仅 lexical-binding 这一项局部变量设置符合此规则;但可通过该变量(一个符号列表)来控制哪些局部变量设置拥有此特性。
该变量是一个目录列表,在这些目录下局部变量会始终启用。从这些目录加载的目录局部变量(例如 .dir-locals.el 文件中的变量),即便存在风险(risky)也会被启用。此列表中的目录必须是完全展开的绝对文件名;若变量 enable-remote-dir-locals 设为非 nil 值,列表中也可包含远程目录。
该函数会解析当前缓冲区内容中指定的所有局部变量,并根据变量类型进行绑定或求值(以合适的方式)。变量 enable-local-variables 在此处会发挥作用。但该函数不会在 ‘-*-’ 行中查找 ‘mode:’ 类型的局部变量 —— 这项工作由 set-auto-mode 完成,且该函数同样会考虑 enable-local-variables 的取值(see Emacs 如何选择主模式)。
此函数还会使 .dir-locals.el 文件中指定的目录局部变量生效。若该缓冲区未关联任何文件,则生效的目录局部变量为那些适用于 default-directory 目录下文件的变量(see 目录局部变量)。
该函数的工作机制为:遍历存储在 file-local-variables-alist 和 dir-local-variables-alist 中的关联列表(alist),并依次处理每个局部变量。它会在处理变量之前调用钩子 before-hack-local-variables-hook,在处理变量之后调用钩子 hack-local-variables-hook。仅当 file-local-variables-alist 为非 nil 值时,才会调用前一个钩子;而后一个钩子则始终会被调用。若某个 ‘mode’ 元素指定的主模式与缓冲区当前已启用的主模式一致,该函数会忽略此元素。
这是严格保留 Texinfo 格式、术语统一、可直接用于编译的简体中文翻译:
如果可选参数 handle-mode 为 t,那么该函数所做的全部工作就是:若 ‘-*-’ 行或局部变量列表指定了主模式,则返回一个表示该主模式的符号,否则返回 nil。它不会设置模式或任何其他文件局部变量。
如果 handle-mode 的值既不是 nil 也不是 t,则会忽略 ‘-*-’ 行或局部变量列表中所有 ‘mode’ 设置,但会应用其他设置。如果 handle-mode 为 nil,则会设置所有文件局部变量。
这个缓冲区局部变量保存着文件局部变量设置的关联列表(alist)。列表中每个元素的格式为 (var . value),其中 var 是局部变量的符号,value 是它的值。
当 Emacs 打开一个文件时,会先将所有文件局部变量收集到这个关联列表中,然后由 hack-local-variables 函数逐一应用这些变量。
Emacs 在即将应用保存在 file-local-variables-alist 中的文件局部变量之前,会立刻调用这个钩子。
Emacs 在应用完保存在 file-local-variables-alist 中的文件局部变量之后,会立刻调用这个钩子。
你可以通过为变量设置 safe-local-variable 属性来指定其安全值。该属性的值必须是一个单参数函数;当传入某个值时,若该函数返回非 nil,则此值即为安全值。许多常见的文件变量都带有 safe-local-variable 属性,包括 fill-column、fill-prefix 和 indent-tabs-mode。对于「值为布尔类型且本身安全」的变量,可将 booleanp 设为此属性的值。
若你希望为在 C 源代码中定义的变量设置 safe-local-variable 属性,需将这些变量的名称及对应的属性添加到 files.el 文件中 “Safe local variables(安全局部变量)” 章节的列表里。
使用 defcustom 定义用户选项时,可通过向 defcustom 添加 :safe function 参数来设置其 safe-local-variable 属性(see 定义自定义变量)。但需注意:通过 :safe 定义的安全谓词,仅在包含该 defcustom 定义的包被加载后才会生效 —— 这往往为时已晚。作为替代方案,你可以使用自动加载标记(see 自动加载)为该选项分配安全谓词,示例如下:
;;;###autoload (put 'var 'safe-local-variable 'pred)
通过 autoload 指定的安全值定义会被复制到包的自动加载文件中(对于 Emacs 自带的大多数包,是 loaddefs.el),并且从会话一开始就对 Emacs 生效。
该变量提供了另一种将某些变量值标记为安全的方式。它是一个由 cons 单元 (var . val) 组成的列表,其中 var 是变量名,val 是对该变量而言安全的值。
当 Emacs 询问用户是否采纳一组文件局部变量设置时,用户可以选择将它们标记为安全。这样做会把这些「变量 / 值」对添加到 safe-local-variable-values 中,并保存到用户的自定义文件里。
如果你希望始终完全忽略某些特定局部变量的某些值,可以使用该变量。它的格式与 safe-local-variable-values 相同;在处理文件指定的局部变量时,与列表中出现的值相匹配的文件局部变量设置将始终被忽略。
与上面那个变量一样,当 Emacs 询问用户是否采纳文件局部变量时,用户可以选择永久忽略它们的特定值,这会修改此变量并保存到用户的自定义文件中。出现在本变量中的「变量‑值」对,优先级高于 safe-local-variable-values 中的相同配对。
基于上述判定标准,若为 sym 赋予值 val 是安全的,则该函数返回非 nil 值。
部分变量会被认定为 高风险(risky) 变量。若一个变量属于高风险类型,它绝不会被自动加入 safe-local-variable-values;除非用户通过直接自定义 safe-local-variable-values 明确允许某个值,否则 Emacs 在设置高风险变量前总会发起询问。
满足以下任一条件的变量会被判定为高风险变量:
nil 的 risky-local-variable 属性;
使用 defcustom 定义用户选项时,可通过向 defcustom 添加 :risky value 参数来设置该属性(see 定义自定义变量)。
如果依据上述判定标准,sym 是一个「有风险的变量」(risky variable),
该函数会返回非 nil 的值
该变量存储一个变量列表,这些变量不应由文件赋予局部值。 为其中任一变量指定的任何值都会被完全忽略。
‘Eval:’ “伪变量(variable)” 同样是一个潜在的安全漏洞, 因此 Emacs 在处理它之前通常会要求用户确认。
该变量控制在被访问文件的 ‘-*-’ 行或局部变量列表中,
对 ‘Eval:’ 的处理行为。值为 t 表示无条件处理;
值为 nil 表示忽略;其他任何值表示针对每个文件询问用户如何处理。
默认值为 maybe。
该变量存储一个表达式列表,当在文件局部变量列表的 ‘Eval:’ “伪变量(variable)” 中 发现这些表达式时,对其求值是安全的。
如果该表达式是一个函数调用,且该函数具有
safe-local-eval-function 属性,那么该属性的值
将决定这个表达式是否可以安全求值。该属性的值可以是:
一个用于测试表达式的断言函数(predicate)、一组此类断言函数的列表
(只要任一断言函数判定成功即视为安全),或 t
(只要参数为常量则始终安全)。
文本属性(text properties)同样是潜在的安全漏洞,因为其值 可能包含待调用的函数。因此 Emacs 会丢弃文件局部变量中指定的 字符串值所附带的所有文本属性。
某个目录可以为其下所有文件指定通用的局部变量值;Emacs 会利用这些值, 在访问该目录下任意文件的缓冲区中,为这些变量创建缓冲区局部绑定 (buffer-local bindings)。当目录中的文件归属于某个 项目(project)、因此需要共享相同的局部变量时,这一功能非常实用。
指定目录局部变量有两种不同方法:一是将其写入一个特殊文件, 二是为该目录定义一个项目类(project class)。
该常量定义了 Emacs 用于查找目录局部变量的文件名。 此文件的默认名称为 .dir-locals.el12。若某个目录下存在该名称的文件,Emacs 会将其中的配置应用到 该目录及其所有子目录下的任意文件(你也可以选择排除子目录,详见下文)。 如果部分子目录自身也包含 .dir-locals.el 文件,Emacs 会从当前文件所在目录开始, 向上遍历目录树,采用找到的最深层文件中的配置。 该常量也用于派生第二个目录局部变量文件 .dir-locals-2.el 的名称。 若此第二个文件与 .dir-locals.el 位于同一目录, 则 Emacs 会在加载 .dir-locals.el 的同时加载该文件。 这一机制的实用场景是:当 .dir-locals.el 被纳入共享代码仓库的版本控制、 无法用于个人自定义配置时,可通过第二个文件实现个性化设置。 该文件以特殊格式的列表指定局部变量;更多细节可参见 按目录配置的局部变量 in GNU Emacs 手册。
该函数会读取 .dir-locals.el 文件,并将目录局部变量存储到
访问该目录下任意文件的缓冲区所专属的 file-local-variables-alist 中,
但 不会 立即应用这些变量。它还会将目录局部配置存储到
dir-locals-class-alist 中,并在该列表里为找到 .dir-locals.el 文件
的目录定义一个特殊的类。此函数的实现逻辑是调用下文所述的
dir-locals-set-class-variables 和 dir-locals-set-directory-class
两个函数。
该函数会查找目录局部变量,并立即将其应用到当前缓冲区中。
它设计用于在非文件缓冲区(如 Dired 缓冲区)的模式命令中调用,
使这类缓冲区也能遵循目录局部变量的配置。对于非文件缓冲区,
Emacs 会在 default-directory(默认目录)及其上级目录中
查找目录局部变量。
该函数为指定的 class(一个符号)定义一组变量配置。你可在后续将该类
分配给一个或多个目录,Emacs 会将这些变量配置应用到这些目录下的所有文件。
variables 中的列表可以是以下两种形式之一:(major-mode . alist)
或 (directory . list)。
对于第一种形式:若文件对应的缓冲区启用了从 major-mode 派生的模式,
则关联的 alist 中的所有变量都会被应用;alist 应采用
(name . value) 的格式。当 major-mode 取特殊值
nil 时,表示这些配置适用于任意模式。在 alist 中,你可使用一个
特殊的 name:subdirs。若其关联值为 nil,则该关联列表仅
应用于对应目录下的文件,而不作用于其子目录中的文件。
对于 variables 的第二种形式:若 directory 是文件所在目录的 初始子串,则会按照上述规则递归应用 list;list 应符合该函数 对 variables 所接受的两种形式之一。
该函数将 class(类)分配给 directory(目录)及其所有子目录下的所有文件。
此后,为 class 指定的所有变量配置都会应用到 directory 及其子目录下
被访问的任意文件。class 必须已通过 dir-locals-set-class-variables
函数完成定义。
Emacs 从 .dir-locals.el 文件加载目录变量时,会在内部调用此函数。
这种情况下,可选参数 mtime 存储的是文件修改时间(由 file-attributes
函数返回)。Emacs 会通过该时间检查已存储的局部变量是否仍有效。
若你是直接分配类(而非通过文件),则该参数应设为 nil。
该关联列表(alist)存储类符号及其对应的变量配置。
它会由 dir-locals-set-class-variables 函数更新。
该关联列表(alist)存储目录名称、其分配的类名,以及对应的目录局部变量文件的
修改时间(若存在该文件)。dir-locals-set-directory-class 函数会更新此列表。
该缓冲区局部变量存储目录局部变量配置的关联列表(alist)。
该关联列表的每个元素格式为 (var . value),其中 var 是
局部变量的符号,value 是其对应值(此结构与 file-local-variables-alist
完全一致,see 文件局部变量)。当 Emacs 访问文件时,
会将所有目录局部变量收集到该列表中,随后 hack-local-variables 函数会逐个
应用这些变量(相关细节同样可参见 文件局部变量)。
这个特殊钩子(hook)存储的函数用于为指定缓冲区收集待使用的目录局部变量。 默认情况下,该钩子仅包含一个函数,即遵循本节所述其他配置规则的函数。 但可通过该钩子扩展对更多目录局部变量来源的支持,例如适配其他文本编辑器 所使用的目录局部变量机制。
该钩子上的函数会在以下时机被调用:无参数调用,且执行上下文为待应用目录局部变量
的目标缓冲区;调用时机为缓冲区的主模式(major-mode)函数运行完毕后。
因此这些函数可借助 major-mode(主模式)或 buffer-file-name(缓冲区文件名)
等信息来源,确定应应用的变量。
它应返回一个格式为 (directory . alist) 的点对单元(cons cell),
或一组此类点对单元组成的列表。返回值为 nil 表示未找到任何目录局部变量。
directory 应为字符串类型:即这些变量所适用的目录名称。
alist 是适用于当前缓冲区的变量及其值的列表,其中每个元素的格式均为
(varname . value)。
这些函数返回的多个 alist 会被合并;若出现配置冲突,目录层级中 更深层目录的配置优先级高于更上层目录的配置。最后需要注意的是, 由于该钩子会在每次访问文件时运行,务必保证这些函数的执行效率, 这通常需要借助某种缓存机制来实现。
若该变量值为 nil,则目录局部变量会被忽略。对于那些希望忽略目录局部变量、
但仍遵守文件局部变量的模式而言,此变量十分实用(详见see 文件局部变量)。
连接局部变量提供了一种通用机制,用于在具有远程连接的缓冲区中使用不同的变量设置(see 远程文件 in GNU Emacs 手册)。这些变量会根据缓冲区所对应的远程连接进行绑定与设置。
Emacs 使用连接局部配置文件(connection-local profiles)来保存要应用到特定连接的变量配置。
之后你可以通过 connection-local-set-profiles 定义生效条件,将这些配置文件与远程连接关联起来。
该函数为连接配置文件 profile(一个符号)定义一组变量配置。
你可以在后续将该连接配置文件分配给一个或多个远程连接,
Emacs 会将这些变量配置应用到这些连接对应的所有进程缓冲区。
variables 列表是一个格式为 (name . value) 的关联列表。
示例:
(connection-local-set-profile-variables
'remote-bash
'((shell-file-name . "/bin/bash")
(shell-command-switch . "-c")
(shell-interactive-switch . "-i")
(shell-login-switch . "-l")))
(connection-local-set-profile-variables
'remote-ksh
'((shell-file-name . "/bin/ksh")
(shell-command-switch . "-c")
(shell-interactive-switch . "-i")
(shell-login-switch . "-l")))
(connection-local-set-profile-variables 'remote-null-device '((null-device . "/dev/null")))
若你希望向已有配置文件追加变量配置,可调用函数 connection-local-get-profile-variables
来获取该配置文件中已有的配置,示例如下:
(connection-local-set-profile-variables 'remote-bash (append (connection-local-get-profile-variables 'remote-bash) '((shell-command-dont-erase-buffer . t))))
该关联列表(alist)存储连接配置文件符号及其对应的变量配置。
它会由 connection-local-set-profile-variables 函数更新。
该函数将符号类型的 profiles(配置文件)分配给所有由 criteria(判定条件)
标识的远程连接。criteria 是一个属性列表(plist),用于标识某一连接
以及使用该连接的应用程序。其属性名可能包括 :application(应用程序)、
:protocol(协议)、:user(用户)和 :machine(主机)。
其中 :application 的属性值为符号类型,其余属性的值均为字符串类型。
所有属性均为可选;若 criteria 为 nil,则该配置始终生效。示例:
(connection-local-set-profiles '(:application tramp :protocol "ssh" :machine "localhost") 'remote-bash 'remote-null-device)
(connection-local-set-profiles
'(:application tramp :protocol "sudo"
:user "root" :machine "localhost")
'remote-ksh 'remote-null-device)
如果 criteria 为 nil,则该配置对所有远程连接都生效。因此,上面的示例等价于:
(connection-local-set-profiles '(:application tramp :protocol "ssh" :machine "localhost") 'remote-bash)
(connection-local-set-profiles
'(:application tramp :protocol "sudo"
:user "root" :machine "localhost")
'remote-ksh)
(connection-local-set-profiles nil 'remote-null-device)
profiles 中的任意一个连接配置文件,都必须已通过
connection-local-set-profile-variables 函数完成定义。
该关联列表(alist)包含连接判定条件及其分配的配置文件名。
connection-local-set-profiles 函数会更新此列表。
在编写感知连接状态的代码时,你需要收集(并可能需要应用)所有相关的连接局部变量。 具体有多种实现方式,下文将逐一说明。
该函数会收集与 criteria(判定条件)相关的、可生效的连接局部变量,
并将其存入 connection-local-variables-alist,但不会立即应用这些变量。
示例:
(hack-connection-local-variables '(:application tramp :protocol "ssh" :machine "localhost"))
connection-local-variables-alist
⇒ ((null-device . "/dev/null")
(shell-login-switch . "-l")
(shell-interactive-switch . "-i")
(shell-command-switch . "-c")
(shell-file-name . "/bin/bash"))
该函数会根据 criteria(判定条件)查找对应的连接局部变量,并立即将其应用到当前缓冲区中。
为 application(应用程序)应用所有关联的连接局部变量,这些变量由 default-directory(默认目录)指定。
完成变量应用后,执行 body(代码体)中的内容,执行结束后撤销已应用的连接局部变量。示例:
(connection-local-set-profile-variables
'my-remote-perl
'((perl-command-name . "/usr/local/bin/perl5")
(perl-command-switch . "-e %s")))
(connection-local-set-profiles '(:application my-app :protocol "ssh" :machine "remotehost") 'my-remote-perl)
(let ((default-directory "/ssh:remotehost:/working/dir/"))
(with-connection-local-application-variables 'my-app
do something useful))
该变量定义了默认应用程序(一个符号),会在
with-connection-local-variables、connection-local-p 以及
connection-local-value 这些宏/函数中生效。其默认值为 tramp,
你可通过 let 绑定的方式临时修改该应用程序(详见see 局部变量)。
该变量禁止全局修改。
该宏的功能与 with-connection-local-application-variables 完全等价,
区别在于它会将 connection-local-default-application 作为默认应用程序使用。
该宏会将每个 symbol(符号)以 连接局部 的方式设置为对应 form(表达式)
求值后的结果,具体使用的连接局部配置文件由 connection-local-profile-name-for-setq 指定;
若该配置文件名的值为 nil,则此宏会像 setq 一样正常设置变量(详见see 修改变量值)。
例如,你可将该宏与 with-connection-local-variables 或
with-connection-local-application-variables 结合使用,
实现连接局部配置的延迟初始化:
(defvar my-app-variable nil) (connection-local-set-profile-variables 'my-app-connection-default-profile '((my-app-variable . nil))) (connection-local-set-profiles '(:application my-app) 'my-app-connection-default-profile)
(defun my-app-get-variable ()
(with-connection-local-application-variables 'my-app
(or my-app-variable
(setq-connection-local my-app-variable
do something useful))))
该变量指定了通过 setq-connection-local 设置变量时要使用的连接局部配置文件名(一个符号)。
在 with-connection-local-variables 的代码体中会对该变量进行 let 绑定,
但如果你希望为其他配置文件设置变量,也可自行对该变量进行 let 绑定。
该变量禁止全局修改。
若 symbol(符号)针对 application(应用程序)存在连接局部绑定,
该宏会返回非 nil 的值。若 application 为 nil,
则使用 connection-local-default-application 的值。
该宏返回 symbol(符号)针对 application(应用程序)的连接局部值。
若 application 为 nil,则使用 connection-local-default-application 的值。
若 symbol 不存在对应的连接局部绑定,该宏会返回该变量的默认绑定值。
若该变量值为 nil,则连接局部变量会被忽略。此变量仅允许在特殊模式下临时修改。
有时将两个变量设为同义词会很实用——这意味着两个变量始终拥有相同的值,
修改其中任意一个也会同步修改另一个。当你需要修改某个变量的名称时(无论是因为发现旧名称命名不当,
还是因为变量的语义发生了部分变化),为了保证兼容性,可将旧名称保留为新名称的 别名。
你可以通过 defvaralias 函数实现这一功能。
该函数将符号 new-alias 定义为符号 base-variable 的变量别名。 这意味着:获取 new-alias 的值时,会返回 base-variable 的值; 修改 new-alias 的值时,也会同步修改 base-variable 的值。 这两个互为别名的变量名始终共享相同的值和相同的绑定关系。
若 docstring(文档字符串)参数的值为非 nil,则该参数会为 new-alias(新别名)指定文档说明;
若该参数为 nil,则这个别名会继承 base-variable(基准变量)的文档说明(如果基准变量有文档说明的话);
但如果 base-variable 本身也是一个别名,那么 new-alias 会继承别名链末端那个变量的文档说明。
该函数的返回值为 base-variable(基准变量)。
若最终形成的变量定义链出现循环引用,Emacs 会抛出 cyclic-variable-indirection(循环变量间接引用)错误。
变量别名可便捷地实现「用新名称替换变量旧名称」的需求。
make-obsolete-variable 函数会标记某个变量的旧名称为「已过时」,
这意味着该旧名称可能会在未来的某个版本中被移除。
该函数会让字节编译器发出警告,提示变量 obsolete-name(过时名称)已过时。 若 current-name 是一个符号,则代表该变量的新名称;此时警告信息会提示应使用 current-name 替代 obsolete-name。若 current-name 是一个字符串, 则该字符串会直接作为警告信息,且表示无替代变量。when 参数应为一个字符串, 用于说明该变量首次被标记为过时的时间(通常是版本号字符串)。
可选参数 access-type 若为非 nil 值,需指定触发过时警告的变量访问类型;
其取值可以是 get(读取)或 set(赋值)。
你可通过宏 define-obsolete-variable-alias 同时实现两个变量的同义绑定,
并将其中一个标记为过时。
该宏会将变量 obsolete-name 标记为过时,同时将其设为变量 current-name 的别名。 它等价于以下代码:
(defvaralias obsolete-name current-name docstring) (make-obsolete-variable obsolete-name current-name when)
该宏会对其所有参数进行求值,且 obsolete-name(过时名称)和 current-name(新名称)都必须是符号类型,因此典型用法如下:
(define-obsolete-variable-alias 'foo-thing 'bar-thing "27.1")
该函数会返回 variable(变量)的别名链末端对应的变量。 若 variable 不是符号类型,或未被定义为别名,则该函数直接返回 variable 本身。
(defvaralias 'foo 'bar)
(indirect-variable 'foo)
⇒ bar
(indirect-variable 'bar)
⇒ bar
(setq bar 2)
bar
⇒ 2
foo
⇒ 2
(setq foo 0)
bar
⇒ 0
foo
⇒ 0
普通的 Lisp 变量可被赋值为任意有效的 Lisp 对象。但部分 Lisp 变量并非由 Lisp 定义,
而是由 C 语言定义。这类变量中,绝大多数是 C 代码通过 DEFVAR_LISP 定义的——
和 Lisp 中定义的变量一样,它们可以接收任意值。不过,还有一些变量是通过
DEFVAR_INT 或 DEFVAR_BOOL 定义的。关于 C 语言层面的实现细节,
see 编写 Emacs 原语,
尤其是对 syms_of_filename 类型函数的说明。
DEFVAR_BOOL 类型的变量仅能取 nil 或 t 两个值。
若尝试为其赋值其他值,该变量会被自动设为 t:
(let ((display-hourglass 5))
display-hourglass)
⇒ t
该变量存储所有 DEFVAR_BOOL 类型变量组成的列表。
DEFVAR_INT 类型的变量仅能接收整数值。若尝试为其赋值其他类型的值,
会直接触发错误:
(setq undo-limit 1000.0) error→ Wrong type argument: integerp, 1000.0
广义变量(generalized variable)或 位置形式(place form),
指的是Lisp内存中可通过 setf 宏存储值的任意位置(see setf 宏)。
最简单的位置形式是普通的Lisp变量,但列表的 CAR 和 CDR 部分、数组的元素、
符号的属性,以及许多其他内存位置,也都属于可存储Lisp值的位置。
广义变量类似于 C 语言中的左值(lvalue)。在 C 语言里, ‘x = a[i]’ 是从数组中取出一个元素,而 ‘a[i] = x’ 则是用同样的写法往数组里存入一个元素。就像在 C 语言中 a[i] 这类表达式可以作为左值一样,在 Lisp 中也有一类表达式可以作为广义变量。
setf 宏 ¶setf 宏是操作广义变量最基础的方式。setf 表达式与 setq 类似,
不同之处在于:它允许每一对参数的第一个(左侧)参数是任意合法的位置形式,而非仅能使用符号。
例如,(setf (car a) b) 会将 a 的 car 部分设为 b,其执行效果与
(setcar a b) 完全一致,但无需为这类位置的赋值和读取操作分别使用两个不同的函数。
该宏会对 form(表达式)进行求值,并将求值结果存储到 place(位置)中,
其中 place 必须是合法的广义变量形式。若传入多组 place 和 form 配对参数,
赋值操作会像 setq 一样按顺序执行。setf 的返回值为最后一个 form 的求值结果。
以下 Lisp 表达式是 Emacs 中可作为广义变量使用的形式,因此可出现在 setf 的 place 参数中:
(setf x y) 与 (setq x y) 完全等价;严格来讲,
既然有了 setf,setq 本身已属冗余。不过出于风格和历史原因,
大多数程序员仍倾向于使用 setq 来设置普通变量。宏 (setf x y)
实际上会展开为 (setq x y),因此在编译后的代码中使用它不会产生性能损耗。
aref cddr symbol-function car elt symbol-plist caar get symbol-value cadr gethash cdr nth cdar nthcdr
alist-get overlay-start default-value overlay-get face-background process-buffer face-font process-filter face-foreground process-get face-stipple process-sentinel face-underline-p terminal-parameter file-modes window-buffer frame-parameter window-dedicated-p frame-parameters window-display-table get-register window-hscroll getenv window-parameter keymap-parent window-point match-data window-start overlay-end
(substring subplace n [m]) 的调用——其中 subplace
本身是一个合法的广义变量,且其当前值为字符串类型,同时待存储的值也必须是字符串。
新字符串会被拼接至目标字符串的指定位置。例如:
(setq a (list "hello" "world"))
⇒ ("hello" "world")
(cadr a)
⇒ "world"
(substring (cadr a) 2 4)
⇒ "rl"
(setf (substring (cadr a) 2 4) "o")
⇒ "o"
(cadr a)
⇒ "wood"
a
⇒ ("hello" "wood")
if 和 cond 也可作为广义变量使用。例如,以下代码会将 foo
或 bar 变量赋值为 zot:
(setf (if (zerop (random 2))
foo
bar)
'zot)
若传入的 place(位置)形式是 setf 无法处理的类型,setf 会触发错误。
需要注意的是,对于 nthcdr 而言,该函数的列表参数本身必须是合法的 place(位置)形式。
例如,(setf (nthcdr 0 foo) 7) 会将 foo 本身赋值为 7。
宏 push(see 修改列表变量)和 pop(see 访问列表元素)
可操作广义变量,而非仅能操作列表。(pop place) 会移除并返回存储在 place 中的列表的第一个元素,
其功能类似于 (prog1 (car place) (setf place (cdr place))),
区别在于它会确保所有子表达式仅求值一次。
(push x place) 会将 x 插入到存储在 place 中的列表的头部,
其功能类似于 (setf place (cons x place)),差异同样体现在子表达式的求值逻辑上。
需注意,在 nthcdr 类型的位置上使用 push 和 pop,
可实现在列表任意位置插入或删除元素。
cl-lib 库为广义变量定义了多种扩展功能,包括新增的 setf 位置形式。
See Generalized Variables in Common Lisp Extensions, Common Lisp 扩展。
setf 形式 ¶本节介绍如何定义可供 setf 操作的新形式。
该宏可让你轻松为简单场景定义 setf 方法。name 为函数、宏或特殊形式的名称。
只要 name 存在与其直接对应的、用于更新它的 setter(赋值函数),
你就可以使用该宏,例如:(gv-define-simple-setter car setcar)。
该宏会将如下形式的调用
(setf (name args...) value)
转换为
(setter args... value)
这类 setf 调用在文档中规定需返回 value(值)。对于 car 和 setcar 这类场景,这一点不会有问题,因为 setcar 本身就会返回它所设置的值。如果你的 setter(赋值函数)不会返回 value,请为 gv-define-simple-setter 的 fix-return 参数传入非 nil 值。此时该宏会展开为等价于以下代码的形式:
(let ((temp value)) (setter args... temp) temp)
以此确保最终返回正确的结果。
该宏支持定义比前文形式更复杂的 setf 展开逻辑。例如,当不存在可直接调用的简单赋值函数时,
或者虽存在赋值函数但该函数所需参数与位置形式的参数不一致时,你可能需要使用该宏。
该宏对 (setf (name args…) value) 形式的表达式进行展开时,
会先根据 arglist(参数列表)绑定 setf 的参数形式 (value args…),
随后执行 body(代码体)。body 应返回一个完成赋值操作的 Lisp 表达式,
且最终需返回被设置的值。以下是该宏的使用示例:
(gv-define-setter caar (val x) `(setcar (car ,x) ,val))
若需要对展开过程进行更精细的控制,可使用 gv-define-expander 宏。例如,可读写的 substring 就可通过如下方式实现:
(gv-define-expander substring
(lambda (do place from &optional to)
(gv-letplace (getter setter) place
(macroexp-let2* (from to)
(funcall do `(substring ,getter ,from ,to)
(lambda (v)
(macroexp-let2* (v)
`(progn
,(funcall setter `(cl--set-substring
,getter ,from ,to ,v))
,v))))))))
gv-letplace 宏可用于定义行为类似 setf 的宏;例如,Common Lisp 中的 incf 宏就可通过如下方式实现:
(defmacro incf (place &optional n)
(gv-letplace (getter setter) place
(macroexp-let2* ((v (or n 1)))
(funcall setter `(+ ,v ,getter)))))
getter 会被绑定为一个可复制的表达式,该表达式返回 place(位置)的值。 setter 会被绑定为一个函数,该函数接收一个表达式 v,并返回一个将 place 设为 v 的新表达式。 body(代码体)应返回一个通过 getter 和 setter 操作 place 的 Emacs Lisp 表达式。
更多细节可参考源码文件 gv.el。
该函数会让字节编译器发出警告,提示广义变量 obsolete-name(过时名称)已过时。 若 current-name 是符号类型,则警告信息会提示应使用 current-name 替代 obsolete-name; 若 current-name 是字符串类型,则该字符串会直接作为警告信息。 when 参数应为字符串类型,用于说明该变量首次被标记为过时的时间(通常为版本号字符串)。
Common Lisp 注意事项: Common Lisp 定义了另一种指定函数
setf行为的方式, 即setf函数 — 这类函数的名称是列表形式(setf name),而非符号。 例如,(defun (setf foo) …)会定义一个函数,当setf作用于foo时会调用该函数。 Emacs 不支持这种方式:若对某个尚未定义对应展开逻辑的表达式使用setf,会触发编译时错误。 而在 Common Lisp 中这并不会报错,因为(setf func)形式的函数可能在后续代码中被定义。
如果你给某个变量赋值,然后关闭 Emacs 再重新启动, 之前赋的值不会自动恢复。 用户通常会在启动文件里设置普通变量,或是使用 Customize(see 自定义设置) 来永久保存用户选项;不同的包也会用各自的文件存储数据 (例如 Gnus 存在 .newsrc.eld,URL 库把 Cookie 存在 ~/.emacs.d/url/cookies)。
在这两种极端做法之间——也就是既要写在启动文件里的配置, 又要单独文件存放的大量应用状态——Emacs 提供了一种 在多次会话之间自动持久化数据的机制,称为 多会话变量(multisession variable)。 (该功能并非在所有系统上都可用。) 下面用一个简单示例说明这类变量的设计用途:
(define-multisession-variable foo 0)
(defun my-adder (num)
(interactive "nAdd number: ")
(setf (multisession-value foo)
(+ (multisession-value foo) num))
(message "The new number is: %s" (multisession-value foo)))
这段代码定义了变量 foo,并将其绑定到一个特殊的多会话对象上——
该对象会以值 ‘0’ 完成初始化(若该变量在前一次会话中尚未存在)。
my-adder 命令会向用户请求输入一个数字,将其与旧值(可能是已保存的值)相加,
随后保存计算后的新值。
该机制并非设计用于存储超大的数据结构, 但对于绝大多数常规值而言,性能表现是可靠的。
该宏将 name 定义为多会话变量; 若该变量此前未被赋值,则为其设置初始值 initial-value。 doc 为文档字符串,args 中可传入多个关键字参数,包括:
:package package-symbol该关键字用于指定多会话变量所属的包,包由 package-symbol(包符号)定义。
package-symbol 与 name(变量名)的组合必须是唯一的。
若未指定 package-symbol,则默认使用 name 符号名称的第一个「分段」——
即名称中第一个 ‘-’(连字符)之前的部分(不包含该连字符)。
例如,若 name 为 foo 且未指定 package-symbol,
则 package-symbol 会默认设为 foo。
:synchronized bool ¶若 bool 为非 nil 值,多会话变量可被设置为 同步(synchronized) 状态。
这意味着:当有两个并发运行的 Emacs 实例时,若另一个 Emacs 实例修改了多会话变量 foo,
当前 Emacs 实例在访问该变量值时,会自动获取这个已修改的数据。
若 synchronized 设为 nil 或未指定该参数,则不会触发同步——
所有使用该变量的 Emacs 会话中,变量值彼此独立、互不影响。
:storage storage使用指定的 storage(存储)方式。可选值为 sqlite(仅在编译时启用 SQLite 支持的 Emacs 中可用)
或 files(文件存储)。若未指定该参数,
则默认使用下文所述 multisession-storage 变量的取值。
该函数返回 variable(变量)的当前值。 若该变量在本次 Emacs 会话中从未被访问过,或其值已被外部修改, 函数会从外部存储中重新读取最新值;否则,直接返回本次会话中的当前值。 若传入的 variable 并非多会话变量,调用该函数会触发错误。
通过 multisession-value 获取的值,彼此之间不一定满足 eq 相等,
但始终满足 equal 相等。
该函数是一个广义变量(详见see 广义变量), 因此更新这类变量的方式示例如下:
(setf (multisession-value foo-bar) 'zot)
只有具备可读打印语法(see 打印表示与读入语法)的 Emacs Lisp 值, 才能通过这种方式保存。
若该多会话变量开启了同步功能,对其赋值时可能会先更新变量值。例如:
(cl-incf (multisession-value foo-bar))
这段代码会先检查该值是否已在另一个 Emacs 实例中被修改: 若有修改则获取该最新值,随后为其加 1 并存储新值。 但需注意,此操作未加锁——因此当多个实例同时更新该值时, 最终哪个实例的修改会 “生效(wins)” 是无法预测的。
该函数会将 object(对象)及其对应的值从持久化存储中删除。
你也可以创建不绑定到特定变量、而是显式绑定到指定包和键的持久化值。
(setq foo (make-multisession :package "mail"
:key "friends"))
(setf (multisession-value foo) 'everybody)
该函数支持与 define-multisession-variable 相同的关键字,
同时新增了 :initial-value 关键字,用于指定默认值。
该变量用于控制多会话变量的存储方式。其默认值为 files,
表示变量值会以「一个变量对应一个文件」的结构,存储在 multisession-directory
指定的目录下。若该变量值设为 sqlite,则变量值会存储在 SQLite 数据库中;
此模式仅在 Emacs 编译时启用了 SQLite 支持的情况下可用。
多会话变量会存储在该目录下,其默认值为 user-emacs-directory
目录的 multisession/ 子目录,通常路径为 ~/.emacs.d/multisession/。
该命令会弹出一个缓冲区,列出所有多会话变量,
并进入一个特殊模式 multisession-edit-mode — 你可在此模式下删除这些变量,或编辑它们的值。
Lisp 程序主要由 Lisp 函数构成。本章讲解什么是函数、函数如何接收参数,以及如何定义函数。
declare 形式从一般意义上讲,函数是一种根据被称为 参数(arguments) 的输入值来执行计算的规则。计算的结果称为该函数的 值(value) 或 返回值(return value)。计算过程也可能产生副作用,例如永久更改变量的值或数据结构的内容(see Definition of side effect)。纯函数(pure function) 是指这样一类函数:它不仅没有副作用,而且对于相同的参数组合,无论外部因素(如机器类型、系统状态)如何,始终返回相同的值。
在大多数编程语言中,每个函数都有名称。但在 Lisp 中,严格意义上的函数本身是没有名字的:它是一个对象,可以可选地与一个符号(如 car)关联,由该符号充当函数名。See 函数命名。当一个函数被赋予名称后,我们通常也将该符号直接称作 “函数(function)” (例如我们说 “car 函数”)。在本手册中,函数名与函数对象本身之间的区别通常并不重要,但在必要时我们会明确区分。
某些类似函数的对象,称为 特殊形式(special forms) 和 宏(macros), 它们也接受参数来执行计算。 但正如后文所述,在 Emacs Lisp 中它们不被视为函数。
以下是函数及类函数对象的重要术语:
用 Lisp 语言编写的函数(严格意义上的函数,即函数对象)。 下一节将会介绍这些内容。 See Lambda 表达式.
可以从 Lisp 中调用,但实际是用 C 语言编写的函数。原语也被称为 内置函数(built-in functions) 或 subr(子例程)。例如 car、append 这类函数都属于原语。此外,所有特殊形式(见下文)也都被视为原语。
一个函数之所以被实现为原语,通常是因为它是 Lisp 的核心基础(如 car),或是需要为操作系统服务提供底层接口,又或是需要具备很高的运行效率。与用 Lisp 定义的函数不同,原语只能通过修改 C 语言源码并重新编译 Emacs 来修改或添加。参见 Writing Emacs Primitives。
一种类似函数的原语,但不会按常规方式对所有参数求值。它可能只对部分参数求值,或以非常规顺序求值,或是对参数多次求值。例如 if、and、while。See 特殊形式。
一种在 Lisp 中定义的语法结构,它与函数的区别在于:宏会将一个 Lisp 表达式转换为另一个表达式,然后对新表达式求值,而非对原表达式直接求值。宏让 Lisp 程序员能够实现特殊形式才能做到的各类功能。See 宏。
可以通过 command-execute 原语调用的对象,通常是因为用户键入了 绑定(bound) 到该命令的按键序列。See 交互式调用。命令通常是函数;如果该函数是用 Lisp 编写的,可在函数定义中通过 interactive 形式将其变为命令 (see 定义命令)。作为函数的命令同样可以在 Lisp 表达式中调用,与普通函数无异。
键盘宏(字符串和向量)虽然不是函数,也属于命令。See 键盘宏。如果一个符号的函数单元中存放着命令,我们就称该符号为命令(see 符号的组成)。这类 命名命令(named command) 可以通过 M-x 调用。
一种与 lambda 表达式十分相似的函数对象,区别在于它还封装了词法变量绑定的环境。 See 闭包。
经过字节编译器编译后的函数。 See 闭包函数类型。
作为真实函数的占位符。当调用该自动加载对象时, Emacs 会先加载包含真实函数定义的文件,随后调用这个真实函数。 See 自动加载。
你可以使用 functionp 函数来检测一个对象是否为函数:
若 object(对象)是任意类型的函数(即可以传递给 funcall 函数调用),
该函数返回 t。需注意:对于作为函数名的符号,functionp 返回 t;
对于作为宏或特殊形式的符号,functionp 返回 nil。
若 object 不是函数,该函数通常返回 nil。
但函数对象的表示形式较为复杂,出于效率考量,在极少数情况下,
即便 object 并非函数,该函数也可能返回 t。
你也可以获取任意函数预期接收的参数数量:
该函数提供指定 function(函数)的参数列表相关信息。
返回值为一个点对(cons cell),格式为 (min . max):
其中 min 是参数的最小数量;
max 则为参数的最大数量——若函数包含 &rest 参数,max 为符号 many;
若 function 是特殊形式,max 为符号 unevalled。
需注意,该函数在部分场景下可能返回不准确的结果,例如以下情况:
apply-partially 定义的函数(see apply-partially)。
advice-add 为其添加了建议的函数(see 为命名函数添加建议)。
与 functionp 不同,后续这些函数 不会 将符号视为其对应的函数定义。
若 object(对象)是内置函数(即 Lisp 原语),该函数返回 t。
(subrp 'message) ; message is a symbol,
⇒ nil ; not a subr object.
(subrp (symbol-function 'message))
⇒ t
若 object(对象)是字节码函数,该函数返回 t。示例如下:
(byte-code-function-p (symbol-function 'next-line))
⇒ t
若 object 是非 ELisp 源码形式的函数对象(而是类似机器码或字节码的形式),
该函数返回 t。更具体地说,当函数满足以下任一条件时,该函数返回 t:
内置函数(也称为 “原语(primitive)” ,see 什么是函数?)、
字节编译函数(see 字节编译)、
原生编译函数(see Lisp 本地代码编译),
或从动态模块加载的函数(see Emacs 动态模块)。
若 object(对象)是解释型函数,该函数返回 t。
若 object 是闭包(一种特定类型的函数对象),该函数返回 t。
目前,所有字节码函数和所有解释型函数均以闭包形式实现。
该函数的功能与 func-arity 类似,但仅适用于内置函数,
且不会进行符号间接解析。若传入非内置函数,该函数会触发错误。
我们建议优先使用 func-arity 而非此函数。
该函数与 functionp 功能类似,区别在于:
对于列表和符号类型的对象,该函数会返回 nil。
若 object(对象)是用 C 语言编写的内置原语(see 原语函数类型),
该函数返回 t。需注意:特殊形式会被明确排除在外,因为它们并非函数。
若你需要同时识别特殊形式,请使用 subr-primitive-p 函数。
Lambda 表达式是用 Lisp 编写的函数对象。以下是一个示例:
(lambda (x) "Return the hyperbolic cosine of X." (* 0.5 (+ (exp x) (exp (- x)))))
在 Emacs Lisp 中,这类列表是合法的表达式,求值后会得到一个函数对象。
Lambda 表达式本身没有名称,它是一种匿名函数(anonymous function)。 尽管 Lambda 表达式可以以这种方式使用(see 匿名函数), 但更常见的用法是将其与符号关联,从而创建命名函数(named functions)(see 函数命名)。 在深入讲解这些细节之前,以下小节会介绍 Lambda 表达式的组成部分及其作用。
Lambda 表达式是一种具有如下结构的列表:
(lambda (arg-variables...) [documentation-string] [interactive-declaration] body-forms...)
Lambda 表达式的第一个元素始终是符号 lambda。
这一设计表明该列表表示一个函数。函数定义以 lambda 开头的原因是:
避免其他用途的列表被误判为合法的函数。
第二个元素是一个符号列表——即参数变量名(see 参数列表的特性), 这部分被称为lambda 列表。当调用一个 Lisp 函数时, 参数值会与 lambda 列表中的变量进行匹配,这些变量会被赋予由传入值构成的局部绑定。 See 局部变量。
文档字符串是置于函数定义内的一个 Lisp 字符串对象,用于为 Emacs 帮助功能描述该函数。 See 函数的文档字符串。
交互式声明是形如 (interactive code-string) 的列表。
该声明用于指定:若函数以交互方式调用,应如何提供参数。
包含此类声明的函数被称为命令(commands);它们可通过 M-x 调用,或绑定到某个按键上。
不打算以这种方式调用的函数不应包含交互式声明。
关于如何编写交互式声明,see 定义命令。
剩余的元素构成函数 体(body):即实现函数功能的 Lisp 代码(或者用 Lisp 程序员的话来说, “一组待求值的 Lisp 形式”)。函数的返回值为函数体最后一个元素的求值结果。
请看以下示例:
(lambda (a b c) (+ a b c))
我们可以将该函数传递给 funcall 来调用它,示例如下:
(funcall (lambda (a b c) (+ a b c))
1 2 3)
此次调用会对 lambda 表达式的函数体进行求值,其中变量
a 绑定为 1、b 绑定为 2、c 绑定为 3。
函数体的求值过程会将这三个数字相加,得到结果 6;
因此,该函数调用返回的值为 6。
需注意,参数也可以是其他函数调用的结果,例如以下示例:
(funcall (lambda (a b c) (+ a b c))
1 (* 2 3) (- 5 4))
该调用会从左到右对参数 1、(* 2 3) 和 (- 5 4) 进行求值。
随后将 lambda 表达式作用于参数值 1、6 和 1,最终得到结果 8。
这些示例表明,你可以使用以 lambda 表达式作为其CAR 部分的形式,
来创建局部变量并为其赋值。在早期的 Lisp 版本中,这是绑定并初始化局部变量的唯一方式。
但如今,使用特殊形式 let 来实现此目的会更清晰(see 局部变量)。
Lambda 表达式如今主要用作匿名函数:既可作为参数传递给其他函数(see 匿名函数),
也可作为符号的函数定义存储,从而生成命名函数(see 函数命名)。
我们这个简单的示例函数 (lambda (a b c) (+ a b c))
指定了三个参数变量,因此调用时必须传入三个参数:
若尝试仅传入两个或四个参数,会触发 wrong-number-of-arguments 错误
(see 错误)。
编写支持省略特定参数的函数往往会带来便利。例如函数 substring
接受三个参数——一个字符串、起始索引和结束索引——但如果省略第三个参数,
其默认值会设为该字符串的 长度。此外,让某些函数支持接收数量不定的参数
也很实用,就像 list 和 + 函数那样。
若要指定函数调用时可省略的可选参数,只需在这些可选参数前加入关键字 &optional 即可。
若要接收零个或多个额外参数(形成参数列表),则在最后一个参数前加入关键字 &rest。
因此,参数列表的完整语法格式如下:
(required-vars... [&optional [optional-vars...]] [&rest rest-var])
方括号表示 &optional 和 &rest 子句及其后续的变量均为可选内容。
调用函数时,每个 required-vars 都需要对应一个实际参数。
零个或多个 optional-vars 可附带实际参数;除非 lambda 列表使用了 &rest,
否则不允许传入超出该范围的实际参数。若使用了 &rest,则可传入任意数量的额外实际参数。
若省略可选变量和剩余变量对应的实际参数,这些变量会默认取值为 nil。
函数无法区分「显式传入的 nil 参数」和「省略的参数」。
不过函数体可自行将 nil 视为其他有意义值的简写形式。
substring 函数正是如此:向其第三个参数传入 nil,
等价于使用所传入字符串的长度作为该参数值。
通用Lisp说明: 通用Lisp允许函数指定可选参数省略时使用的默认值; 而Emacs Lisp始终将
nil作为默认值。Emacs Lisp不支持通过supplied-p变量判断参数是否被显式传入。
例如,形如下面这样的参数列表:
(a b &optional c d &rest e)
该参数列表会将 a 和 b 绑定到前两个实际参数(这两个参数为必传项)。
若传入更多的一个或两个参数,则 c 和 d 会分别绑定到这些参数;
前四个参数之后的所有参数会被收集为一个列表,e 则绑定到该列表。
因此:若仅传入两个参数,c、d 和 e 的值均为 nil;
若传入两个或三个参数,d 和 e 的值为 nil;
若传入四个及以下参数,e 的值为 nil。
需注意:若恰好传入五个参数,且为 e 显式传入 nil 作为参数,
该 nil 参数会以包含一个元素的列表(即 (nil))形式传递给 e——
这与为 e 传入任何其他单一值的处理方式一致。
必选参数不能出现在可选参数之后——这种写法在逻辑上毫无意义。
要理解为何必须遵循此规则,不妨假设示例中的 c 为可选参数、d 为必选参数:
若传入三个实际参数,第三个参数应绑定到哪个变量?是绑定给 c,还是 d?
两种解读都能找到理由。同理,在 &rest 参数之后也不能再出现任何参数
(无论是必选参数还是可选参数),这同样不符合逻辑。
以下是一些参数列表及合法调用的示例:
(funcall (lambda (n) (1+ n)) ; One required: 1) ; requires exactly one argument. ⇒ 2 (funcall (lambda (n &optional n1) ; One required and one optional: (if n1 (+ n n1) (1+ n))) ; 1 or 2 arguments. 1 2) ⇒ 3 (funcall (lambda (n &rest ns) ; One required and one rest: (+ n (apply '+ ns))) ; 1 or more arguments. 1 2 3 4 5) ⇒ 15
Lambda 表达式可以在形参列表之后可选地包含一段 文档字符串(documentation string)。这段字符串不会影响函数的执行;它类似一种注释,但属于结构化注释,真实存在于 Lisp 环境中,并可被 Emacs 的帮助系统使用。See 文档 章节介绍了如何访问文档字符串。
为程序中的所有函数提供文档字符串是一个好习惯,即便是那些只在程序内部被调用的函数也应如此。文档字符串与普通注释类似,区别在于它们更容易被访问。
文档字符串的第一行应当独立成意,因为 apropos 只会显示这一行。它应该由一到两句完整的句子组成,概括函数的用途。
文档字符串在源文件中通常会有缩进,但由于这些空格位于起始双引号之前,它们不属于字符串本身。有些人会习惯将字符串里后续的行也做缩进,让源码里看起来对齐。这是错误的做法。后续行的缩进会被包含在字符串内部;在源码里看起来整齐的格式,在帮助命令显示时会变得杂乱难看。
文档字符串后面必须至少跟随一个 Lisp 表达式;否则,它根本不算文档字符串,而会被当作函数体里的单个表达式,并作为返回值使用。
当函数没有有意义的值需要返回时,标准做法是在文档字符串后添加 nil 并将其返回。
文档字符串的最后一行可以用来指定与实际函数参数不同的调用规范。可以像这样书写文本:
\(fn arglist)
在一个空行之后、行首位置书写该行,并且在文档字符串内部该行之后不能换行。(其中的 ‘\’ 用于避免干扰 Emacs 的移动命令。)以这种方式指定的调用规范会出现在帮助信息中,替代从函数实际参数推导出来的调用格式。
该特性对宏定义特别有用,因为宏定义中书写的参数往往不符合用户对宏调用各部分的直观理解。
如果你希望弃用旧的调用规范,并推荐使用上述方式声明的规范,请不要使用该特性。
请改用 advertised-calling-convention 声明(see declare 形式)或 set-advertised-calling-convention(see 声明函数为废弃状态)。因为当字节编译器编译使用了被弃用调用规范的 Lisp 程序时,这两种方式会使其生成警告信息。
(fn) 特性通常用于以下场景:
(defmacro lambda (&rest cdr) "... \(fn ARGS [DOCSTRING] [INTERACTIVE] BODY)"...)
(defmacro macroexp--accumulate (var+list &rest body) "... \(fn (VAR LIST) BODY...)" (declare (indent 1)) (let ((var (car var+list)) (list (cadr var+list)) ...)))
defalias 的用途。示例:
(defalias 'abbrev-get 'get "... \(fn ABBREV PROP)")
文档字符串通常是静态的,但有时需要动态生成。在某些情况下,你可以编写一个宏,在编译时生成包含所需文档字符串的函数代码。不过,你也可以用 (:documentation form) 代替文档字符串,来动态生成它。这会在函数定义时运行时求值 form,并将其作为文档字符串 13。你还可以在文档字符串被查询时即时计算它:只需将函数符号的function-documentation 属性设置为一个求值结果为字符串的 Lisp 表达式。
示例:
(defun adder (x)
(lambda (y)
(:documentation (format "Add %S to the argument Y." x))
(+ x y)))
(defalias 'adder5 (adder 5))
(documentation 'adder5)
⇒ "Add 5 to the argument Y."
(put 'adder5 'function-documentation
'(concat (documentation (symbol-function 'adder5) 'raw)
" Consulted at " (format-time-string "%H:%M:%S")))
(documentation 'adder5)
⇒ "Add 5 to the argument Y. Consulted at 15:52:13"
(documentation 'adder5)
⇒ "Add 5 to the argument Y. Consulted at 15:52:18"
一个符号可以作为函数的名称。当符号的 函数单元(function cell)(see 符号的组成)中存放了一个函数对象(例如 lambda 表达式)时,就会形成这种情况。此时,符号本身就成为一个合法、可调用的函数,等价于其函数单元中的函数对象。
函数单元里的内容也被称为该符号的 函数定义(function definition)。使用符号的函数定义来代替符号本身的过程,称为 符号函数间接解析(symbol function indirection);参见 符号函数间接引用。 如果你没有为某个符号设置函数定义,它的函数单元就被称为 无效(void),该符号也就不能用作函数。
在实际使用中,几乎所有函数都有名称,并且通过名称来引用。你可以通过定义一个 lambda 表达式并将其放入函数单元来创建一个命名的 Lisp 函数(see 访问函数单元内容)。不过,更常见的做法是使用下一节介绍的 defun 宏。
See 定义函数.
我们为函数命名,是因为在 Lisp 表达式中通过名称引用函数会很方便。此外,命名函数可以轻松地引用自身 —— 即可以是递归的。更进一步说,原语只能通过名称以文本形式引用,因为原语函数对象(see 原语函数类型)没有可读语法。
一个函数不必拥有唯一的名称。一个给定的函数对象 通常 只出现在一个符号的函数单元中,但这只是一种约定。使用 fset 可以很容易地将它存入多个符号,这样每个符号都成为同一个函数的有效名称。
注意:用作函数名的符号,也可以同时用作变量;符号的这两种用途是相互独立、互不冲突的。(这一点在某些 Lisp 方言中并不成立,比如 Scheme。)
按照约定,如果一个函数的符号由 ‘--’ 分隔的两部分组成,说明该函数是内部使用的,且第一部分对应定义该函数的文件名。例如,名为 vc-git--rev-parse 的函数,就是定义在 vc-git.el 中的内部函数。用 C 语言编写的内部函数,名称以 ‘-internal’ 结尾,例如 bury-buffer-internal。2018 年之前提交的 Emacs 代码可能遵循其他内部命名约定,这些约定正在逐步淘汰。
我们通常在创建函数时为其命名。这一过程称为 定义函数(defining a function),一般通过 defun 宏来完成。本节还会介绍其他定义函数的方式。
defun 是定义新 Lisp 函数的常用方式。它将符号 name 定义为一个函数,参数列表为 args(see 参数列表的特性),函数体为 body 中的表达式。name 和 args 都不需要加引号。
doc(若存在)应为字符串,用作函数的文档字符串(see 函数的文档字符串)。declare(若存在)应为 declare 形式,用于指定函数元数据(see declare 形式)。interactive(若存在)应为 interactive 形式,用于指定函数的交互式调用方式(see 交互式调用)。
defun 的返回值未定义。
以下是一些示例:
(defun foo () 5)
(foo)
⇒ 5
(defun bar (a &optional b &rest c)
(list a b c))
(bar 1 2 3 4 5)
⇒ (1 2 (3 4 5))
(bar 1)
⇒ (1 nil nil)
(bar) error→ Wrong number of arguments.
(defun capitalize-backwards () "Upcase the last letter of the word at point." (interactive) (backward-word 1) (forward-word 1) (backward-char 1) (capitalize-word 1))
大多数 Emacs 函数都是 Lisp 程序源代码的一部分,在 Emacs Lisp 读取器执行程序之前读取源码时就已定义。不过,你也可以在运行时动态定义函数,例如:在程序代码执行时生成 defun 调用。
如果这样做,需要注意:Emacs 的帮助命令(如 C-h f)会在 *Help* 缓冲区中提供一个跳转到函数定义的按钮,但这类命令可能无法找到动态生成函数的源代码。因为动态生成函数的写法,与通常静态调用 defun 的形式差异很大。
你可以使用 definition-name 属性,让帮助系统更容易找到生成这类函数的代码,详见 see 标准符号属性。
请注意不要无意地重定义已存在的函数。defun 甚至会毫无提示、毫无顾忌地重定义 car 这类原语函数。Emacs 不会阻止你这样做,因为有时候重定义是故意为之,而系统无法区分有意与无意的重定义。
该函数将符号 name 定义为一个函数,其函数定义为 definition。definition 可以是任意合法的 Lisp 函数、宏、特殊形式(see 特殊形式)、键映射(see 按键映射),也可以是向量或字符串(表示键盘宏)。defalias 的返回值未定义。
若 doc 不为 nil,则其会成为 name 对应的函数文档。否则,将使用 definition 自身携带的任何文档(如果有)。
在内部实现上,defalias 通常使用 fset 来设置函数定义。但如果 name 拥有 defalias-fset-function 属性,则会调用该属性关联的值(一个函数),以替代 fset 完成设置。
defalias 的适用场景是:定义特定的函数 / 宏名称时 ——尤其是在被加载的源码文件中显式出现该名称的场景。这是因为 defalias 会记录函数的定义文件(与 defun 行为一致,see 卸载)。
与之相反,在以其他目的操作函数定义的程序中,更适合使用 fset(该函数不会保留这类文件记录)。详见 see 访问函数单元内容。
如果最终形成的函数定义链出现循环,那么Emacs 会抛出一个 cyclic-function-indirection 错误。
检查 object 是否为函数别名。若是,则返回一个由符号组成的列表,代表该函数别名链;否则返回 nil。例如,若 a 是 b 的别名,且 b 是 c 的别名:
(function-alias-p 'a)
⇒ (b c)
该函数还有第二个可选参数,但此参数已废弃(obsolete)且无任何实际作用。
你无法使用 defun 或 defalias 创建新的原语函数(primitive function),但可以通过它们修改任意符号的函数定义 —— 即便是 car 或 x-popup-menu 这类默认定义为原语的符号也不例外。不过这种操作存在风险:例如,重新定义 car 几乎必然会导致整个 Lisp 语言彻底无法正常工作。重新定义 x-popup-menu 这类不常用的函数风险相对较低,但仍可能无法达到你预期的效果。如果有 C 代码直接调用该原语函数,这些调用会直接执行原语的 C 语言定义,因此修改符号的函数定义不会对其产生任何影响。
另请参见 defsubst,它与 defun 类似,用于定义函数,同时会告知 Lisp 编译器对该函数执行内联展开。See 内联函数。
若要取消定义某个函数名,可使用 fmakunbound。See 访问函数单元内容。
定义函数只是完成了一半工作。函数在被你 调用(call)(即指令其运行)之前不会执行任何操作。调用函数也被称为 启用(invocation)。
调用函数最常见的方式是对列表进行求值。例如,对列表 (concat "a" "b") 求值时,会调用函数 concat,并传入参数 "a" 和 "b"。有关求值的详细说明,see Evaluation。
当你在程序中将列表编写为表达式时,会在程序文本中明确指定要调用的函数,以及要传入的参数数量。通常情况下,这正是你所需要的。但偶尔你需要在运行时计算确定要调用的函数 —— 此时可使用函数 funcall。如果还需要在运行时确定要传递的参数数量,则使用 apply。
funcall 会调用 function 并传入 arguments 参数,最终返回 function 的执行结果。
由于 funcall 本身是一个函数,其所有参数(包括 function)都会在 funcall 被调用之前完成求值。这意味着你可以通过任意表达式来获取待调用的函数;同时也意味着 funcall 不会直接处理你为 arguments 编写的表达式,只会处理这些表达式的值。在调用 function 的过程中,这些值不会被二次求值 ——funcall 的执行逻辑与普通函数调用的流程一致,区别仅在于它的参数已提前完成求值。
参数 function 必须是一个 Lisp 函数或原语函数(primitive function)。特殊形式(special forms)和宏(macros)不被允许作为该参数 —— 因为它们只有在接收未求值的参数表达式时才有意义。而 funcall 无法满足这一要求,正如我们上文所述,它从一开始就无法获取这些未求值的表达式。
如果你需要使用 funcall 调用一个命令,并使其表现得如同以交互方式被调用,可使用 funcall-interactively(see 交互式调用)。
(setq f 'list)
⇒ list
(funcall f 'x 'y 'z)
⇒ (x y z)
(funcall f 'x 'y '(z))
⇒ (x y (z))
(funcall 'and t nil) error→ Invalid function: #<subr and>
将这些示例与 apply 的示例进行对比。
apply 调用 function 并传入 arguments 参数,其行为与 funcall 基本一致,仅存在一处差异:arguments 中的最后一项需为一个对象列表,该列表内的元素会作为独立参数传递给 function,而非将整个列表作为单个参数传入。我们称 apply 会 展开(spreads) 这个列表,使列表中的每个独立元素都成为一个参数。
仅传入单个参数的 apply 属于特殊情况:该参数必须是非空列表,列表的第一个元素会被当作函数调用,剩余元素则作为独立参数传入该函数。传入两个或更多参数时,apply 的执行效率会更高。
apply 返回调用 function 后的结果。与 funcall 相同,function 必须是 Lisp 函数或原语函数(primitive function);特殊形式(special forms)和宏(macros)在 apply 中无法正常生效。
(setq f 'list)
⇒ list
(apply f 'x 'y 'z) error→ Wrong type argument: listp, z
(apply '+ 1 2 '(3 4))
⇒ 10
(apply '+ '(1 2 3 4))
⇒ 10
(apply 'append '((a b c) nil (x y z) nil))
⇒ (a b c x y z)
(apply '(+ 3 4))
⇒ 7
关于使用 apply 的一个实用示例,可参见 Definition of mapcar。
有时,将函数的部分参数固定为特定值,仅保留剩余参数待函数实际调用时传入,会非常实用。这种固定函数部分参数的操作被称为函数的 部分应用(partial application)14。 该操作的结果是生成一个新函数 —— 它接收剩余的参数,并将所有参数(固定参数 + 新传入参数)合并后调用原函数。
以下是在 Emacs Lisp 中实现函数部分应用的方法:
该函数会返回一个新函数;当这个新函数被调用时,它会将 args 中的参数与调用新函数时传入的额外参数合并为参数列表,再调用 func。若 func 接收 n 个参数,那么以 m <= n 个参数调用 apply-partially 时,会生成一个接收 n - m 个参数的新函数 15。
假设内置函数 1+ 不存在,我们可以通过 apply-partially 和另一个内置函数 + 来定义它,示例如下 16:
(defalias '1+ (apply-partially '+ 1) "Increment argument by one.")
(1+ 10)
⇒ 11
Lisp 函数常接收其他函数作为参数,或从数据结构(尤其钩子变量(hook variables)和属性列表(property lists))中查找函数,并通过 funcall 或 apply 调用它们。这类接收函数作为参数的函数通常被称为 函数式函数(functionals)。
有时调用函数式函数时,传入一个空操作(no-op)函数作为参数会很实用。以下是三种不同类型的空操作函数:
该函数返回 argument,且无任何副作用(side effects)。
该函数忽略所有 arguments,并返回 nil。
该函数忽略所有 arguments,并返回 t。
部分函数是用户可见的 命令(commands),可通过交互方式调用(通常通过按键序列)。使用 call-interactively 函数,能够完全模拟交互式调用的方式来执行这类命令。See 交互式调用。
映射函数(mapping function) 会将指定函数(注意:不能是 特殊形式或宏)应用于序列(如列表、向量或字符串)的每个元素(see 序列、数组与向量)。Emacs Lisp 提供了多个此类函数;本节介绍 mapcar、mapc、mapconcat 和 mapcan—— 这些函数用于遍历序列并执行映射操作。关于遍历符号表(obarray)中所有符号的 mapatoms 函数,See Definition of mapatoms;关于遍历哈希表中键值对的 maphash 函数,see Definition of maphash。
这些映射函数无法作用于字符表(char-table)—— 因为字符表是一种稀疏数组,其标称索引范围极大。若要适配字符表的稀疏特性进行遍历映射,需使用 map-char-table 函数(see 字符表)。
mapcar 会依次将 function 应用于 sequence 的每个元素,并返回由所有执行结果组成的列表。
参数 sequence 可以是除字符表(char-table)之外的任意类型序列;具体包括列表(list)、向量(vector)、布尔向量(bool-vector)或字符串(string)。返回结果始终为一个列表,且结果的长度与 sequence 的长度完全一致。例如:
(mapcar #'car '((a b) (c d) (e f)))
⇒ (a c e)
(mapcar #'1+ [1 2 3])
⇒ (2 3 4)
(mapcar #'string "abc")
⇒ ("a" "b" "c")
;; Call each function in my-hooks.
(mapcar 'funcall my-hooks)
(defun mapcar* (function &rest args) "Apply FUNCTION to successive cars of all ARGS. Return the list of results." ;; If no list is exhausted, (if (not (memq nil args)) ;; apply function to CARs. (cons (apply function (mapcar #'car args)) (apply #'mapcar* function ;; Recurse for rest of elements. (mapcar #'cdr args)))))
(mapcar* #'cons '(a b c) '(1 2 3 4))
⇒ ((a . 1) (b . 2) (c . 3))
该函数会将 function 应用于 sequence 的每个元素,行为与 mapcar 类似;但与 mapcar 收集结果到列表中不同的是,它会通过修改(借助 nconc 函数;see 重排列表的函数)这些结果(要求结果必须是列表),最终返回一个包含所有结果元素的单一列表。和 mapcar 一样,sequence 可以是除字符表(char-table)之外的任意类型序列。
;; Contrast this: (mapcar #'list '(a b c d)) ⇒ ((a) (b) (c) (d)) ;; with this: (mapcan #'list '(a b c d)) ⇒ (a b c d)
mapc 的行为与 mapcar 类似,区别在于 function 仅用于产生副作用 — 其返回值会被忽略,不会被收集到列表中。mapc 的返回值始终是 sequence 本身。
mapconcat 会将 function 应用于 sequence 的每个元素;函数执行结果(必须是字符序列,如字符串、向量或列表)会被拼接为一个单一字符串作为返回值。在每两个结果序列之间,mapconcat 会插入 separator 中的字符 ——separator 也必须是字符串、字符向量或字符列表;若 separator 为 nil,则会被视作空字符串。See 序列、数组与向量。
参数 function 必须是一个可接收单个参数、且返回字符序列(字符串、向量或列表)的函数。参数 sequence 可以是除字符表(char-table)之外的任意类型序列;具体包括列表、向量、布尔向量(bool-vector)或字符串。
(mapconcat #'symbol-name
'(The cat in the hat)
" ")
⇒ "The cat in the hat"
(mapconcat (lambda (x) (format "%c" (1+ x)))
"HAL-8000")
⇒ "IBM.9111"
尽管函数通常通过 defun 定义并同时赋予名称,但有时使用显式的 lambda 表达式 —— 即 匿名函数(anonymous function) 会更为便捷。匿名函数可在任何能使用函数名的场景下生效,常被赋值给变量,或作为函数的参数使用;例如,你可以将一个匿名函数作为 function 参数传递给 mapcar,由 mapcar 将该函数应用到列表的每个元素上(see 映射函数)。相关实际应用示例,see describe-symbols example。
若要定义用作匿名函数的 lambda 表达式,应使用 lambda 宏、function 特殊形式,或 #' 读取语法:
该宏会返回一个匿名函数,其参数列表为 args、文档字符串为 doc(若有)、交互式规范为 interactive(若有),函数体由 body 给出的若干形式构成。
例如,这个宏使得 lambda 形式几乎自引用:对一个首元素(CAR)为 lambda 的表达式进行求值,得到的值与该表达式本身几乎一样:
(lambda (x) (* x x))
⇒ #f(lambda (x) :dynbind (* x x))
在词法绑定下求值时,结果是一个类似的闭包对象,其中 :dynbind 标记会被捕获的变量所替换(see 闭包)。
lambda 表达式还有一个作用:它通过将 function 作为子程序使用(见下文),告知 Emacs 求值器与字节编译器其参数是一个函数。
这个特殊形式会返回 function-object 的函数值。在很多方面,它与 quote 类似(see 引用)。但与 quote 不同的是,它同时还向 Emacs 求值器和字节编译器标记:function-object 是 “intended to be used as a function(意图作为函数使用)”。
假设 function-object 是合法的 lambda 表达式,这会产生两个效果:
当 function-object 是一个符号且代码被字节编译时,若该函数未定义或在运行时可能无法被识别,字节编译器会发出警告。
读取语法 #' 是使用 function 的简写形式。以下形式完全等效:
(lambda (x) (* x x)) (function (lambda (x) (* x x))) #'(lambda (x) (* x x))
在下面的示例中,我们定义了一个 change-property 函数,该函数接受一个函数作为第三个参数;随后定义了 double-property 函数,它通过向 change-property 传入一个匿名函数来使用该函数:
(defun change-property (symbol prop function)
(let ((value (get symbol prop)))
(put symbol prop (funcall function value))))
(defun double-property (symbol prop) (change-property symbol prop (lambda (x) (* 2 x))))
请注意,我们并未对 lambda 表达式进行引用(quote)。
如果你编译上述代码,这个匿名函数也会被编译。但假如你是通过将匿名函数作为列表进行引用(quote)的方式来构造它,情况就不同了:
(defun double-property (symbol prop) (change-property symbol prop '(lambda (x) (* 2 x))))
在这种情况下,该匿名函数会以 lambda 表达式的形式保留在编译后的代码中。即便这个列表看起来像一个函数,字节编译器也无法认定它就是函数 —— 因为编译器并不知道 change-property 意图将其用作函数。
使用 defun 定义的函数,对其参数的类型和预期取值有着固定的预设。例如,一个设计用来处理数字或数字列表的函数,如果传入其他类型的值(如向量或字符串),就会运行失败或抛出错误。这是因为函数的实现并没有准备好处理设计时预设之外的类型。
与之相对,面向对象程序使用 多态函数(polymorphic functions):一组同名的专用函数,每一个都针对某一组特定的参数类型编写。实际调用哪一个函数,会在运行时根据实际参数的类型来决定。
Emacs 提供了对多态的支持。与其他 Lisp 环境(尤其是 Common Lisp 及其公共 Lisp 对象系统 CLOS)类似,这一支持基于 泛型函数(generic functions)。Emacs 的泛型函数高度遵循 CLOS 规范,包括使用相似的命名。因此,如果你有 CLOS 使用经验,本节后续内容会让你感到非常熟悉。
泛型函数通过定义其名称与参数列表来指定一个抽象操作,但(通常)不提供实现。针对若干特定类参数的实际实现由 方法(methods) 提供,这些方法需要单独定义。实现某个泛型函数的每个方法都与该泛型函数同名,但方法的定义会通过对泛型函数所定义的参数进行 特化(specializing),来表明它可以处理哪些类型的参数。这些 参数特化符(argument specializers) 可以更具体或更一般;例如,string 类型就比更一般的类型(如 sequence)更加具体。
注意,与基于消息的面向对象语言(如 C++ 和 Simula)不同,实现泛型函数的方法并不属于某个类,而是属于它们所实现的泛型函数。
当调用一个泛型函数时,它会将调用者传入的实际参数与每个方法的参数特化符进行比较,从而选出适用的方法。如果调用的实际参数与某个方法的特化符兼容,则该方法是适用的。如果有多个方法适用,则会按照后面描述的特定规则将它们组合起来,由组合后的结果处理此次调用。
该宏用于定义一个泛型函数,指定其 name(名称)和 arguments(参数列表)。若提供了 body(函数体),则该部分会作为泛型函数的默认实现;若提供了 documentation(文档说明,建议始终提供),则需以 (:documentation docstring) 的形式指定泛型函数的文档字符串。可选的 options-and-methods 参数可采用以下形式之一:
(declare declarations)声明形式(declare form),具体说明参见 declare 形式。
(:argument-precedence-order &rest args)该形式会影响适用方法组合时的排序规则。默认情况下,组合过程中比较两个方法时,会从左到右检查方法参数,第一个参数特化符更具体的方法会排在前面;而该形式定义的顺序会覆盖这一默认规则 —— 参数检查顺序将按照此形式中 args 的排列顺序执行,而非从左到右。
(:method [qualifiers…] args &rest body)该形式定义一个方法,功能与 cl-defmethod 一致。
该宏为名为 name 的泛型函数定义一个具体实现。实现代码由 body(函数体)提供;若存在 docstring,则其为该方法的文档字符串。
arguments(参数列表)需满足两个要求:一是实现同一泛型函数的所有方法,其参数列表必须完全一致;二是必须与该泛型函数的参数列表匹配。该参数列表以 (arg spec) 的形式提供参数特化符—— 其中 arg 是 cl-defgeneric 调用中指定的参数名,spec 可为以下特化符形式之一:
type此特化符要求参数必须是指定的 type(类型),即下文所述类型层级中的某一种类型。
(eql object)此特化符要求参数必须与指定的 object(对象)满足 eql 相等性。
(head object)参数必须是一个 cons 单元,且其 car 部分与 object 满足 eql 相等性。
struct-type参数必须是通过 cl-defstruct 定义的、名为 struct-type 的类的实例(see Structures in Common Lisp Extensions for GNU Emacs Lisp),或该类任一子类的实例。
方法定义中可以使用一个新的参数列表关键字 &context,它用于引入额外的环境特化符,在方法运行时对当前环境进行检测。该关键字应出现在必选参数列表之后,但在任何 &rest 或 &optional 关键字之前。
&context 特化符的写法与普通参数特化符非常相似 — 形式为 (expr spec) — 区别在于:expr 是要在当前上下文中求值的表达式,而 spec 是用于比较的值。例如,&context (overwrite-mode (eql t)) 会让该方法仅在 overwrite-mode 开启时才适用。&context 关键字后可以跟随任意数量的环境特化符。由于环境特化符不属于泛型函数的参数签名,不需要它们的方法中可以省略。
类型特化符 (arg type) 可以指定下表中的一种 系统类型(system types)。当指定了一个父类型时,任何属于其更具体的子类型、孙类型、重孙类型等的参数,都将视为兼容。
integerParent type: number.
numbernullParent type: symbol
symbolstringParent type: array.
arrayParent type: sequence.
consParent type: list.
listParent type: sequence.
markeroverlayfloatParent type: number.
window-configurationprocesswindowsubrcompiled-functionbufferchar-tableParent type: array.
bool-vectorParent type: array.
vectorParent type: array.
framehash-tablefont-specfont-entityfont-object可选的 extra 部分以 ‘:extra string’ 的形式书写,它允许你为相同的特化符与限定符添加更多方法,这些方法通过 string 加以区分。
可选的 qualifier(限定符)用于对多个适用方法进行组合。如果不指定该参数,则定义的方法为 主方法(primary method),负责为经过特化的参数提供泛型函数的主要实现。你也可以将以下值之一用作 qualifier,以定义 辅助方法(auxiliary methods):
:before该辅助方法会在主方法之前执行。更准确地说,所有 :before 方法都会按最具体优先的顺序在主方法之前运行。
:after该辅助方法会在主方法之后执行。更准确地说,所有此类方法都会按最具体最后的顺序在主方法之后运行。
:around该辅助方法会 替代 主方法执行。此类方法中最具体的那个会先于其他所有方法执行。这类方法通常会使用下文介绍的 cl-call-next-method 来调用其他辅助方法或主方法。
使用 cl-defmethod 定义的函数无法通过添加 interactive 形式变为交互式函数(即命令,see 定义命令)。若你需要一个多态命令,建议先定义一个普通命令,再让该命令调用通过 cl-defgeneric 和 cl-defmethod 定义的多态函数。
每次调用泛型函数时,它都会构建一个 有效方法(effective method)—— 该方法通过组合为当前函数定义的所有适用方法,来处理此次调用。查找适用方法并生成有效方法的过程被称为 分派(dispatch)。 适用方法指的是:其所有特化符均与调用时传入的实际参数兼容的方法。由于所有参数都必须与特化符兼容,因此所有参数都会共同决定某个方法是否适用。显式对多个参数进行特化的方法被称为 多分派方法(multiple-dispatch methods)。
适用的方法会按照其组合执行的顺序进行排序。最左侧参数特化器(argument specializer) 最为具体的方法会排在该顺序的首位。(如上文所述,在 cl-defmethod 中指定 :argument-precedence-order 会覆盖这一默认排序规则。)若方法体调用了 cl-call-next-method,则会执行下一个次具体的方法。如果存在适用的 :around方法,其中最具体的 :around 方法会最先执行;该方法应调用 cl-call-next-method 以执行其余较不具体的 :around 方法。接下来, :before 方法会按其具体程度从高到低执行,随后执行主方法(primary method),最后 :after 方法会按其具体程度从低到高(即反向)执行。
当在主方法或 :around 辅助方法的词法作用域内调用此函数时,它会为同一个泛型函数调用下一个适用的方法。通常情况下,调用时不传入任何参数,这意味着会使用调用当前方法的同一组参数来调用下一个适用的方法。若传入了参数,则会改用指定的参数执行。
此函数在主方法或 :around 辅助方法的词法作用域内被调用时,若存在可调用的下一个方法,则返回非 nil 值;否则返回 nil。
符号的 函数定义(function definition) 是存储在该符号函数单元(function cell)中的对象。本节描述的函数用于访问、检测和设置符号的函数单元。
另请参见函数 indirect-function。See Definition of indirect-function。
返回 symbol(符号)的函数单元中存放的对象。本函数不检查返回的对象是否为合法函数。如果该函数无效(void),返回值为 nil。
(defun bar (n) (+ n 2))
(symbol-function 'bar)
⇒ #f(lambda (n) [t] (+ n 2))
(fset 'baz 'bar)
⇒ bar
(symbol-function 'baz)
⇒ bar
如果您从未为某个符号定义过任何函数,那么该符号的函数单元会包含默认值 nil,此时我们称这个函数为 空函数(void)。若您尝试将该符号当作函数调用,Emacs 会抛出 void-function(空函数)错误。
与空变量不同(see 变量为空的情况),符号的函数单元中存储 nil,和该函数处于 “空” 状态这两种情况是无法区分的。请注意,“空(void)”并非等同于符号 void:只要您通过 defun 为 void定义函数体,它就可以成为一个有效的函数。
您可以使用 fboundp 函数检测符号的函数定义是否为空。当您为符号定义函数后,若想再次将其置为空函数,可调用 fmakunbound 函数。
该函数的作用是:如果符号的函数单元中存储的是非 nil 对象,则返回 t;否则返回 nil。此函数不会检查该对象是否为合法的函数。
该函数会将 symbol 的函数单元设为 nil,后续若尝试访问该函数单元,会触发 void-function 错误。函数的返回值为 symbol。(另见 变量为空的情况 中介绍的 makunbound 函数。)
(defun foo (x) x)
(foo 1)
⇒1
(fmakunbound 'foo)
⇒ foo
(foo 1) error→ Symbol's function definition is void: foo
该函数会将 definition(定义内容)存入 symbol(符号)的函数单元中,返回值为 definition。通常情况下,definition 应当是一个函数或函数名,但该函数并不会对此做检查。参数 symbol 是一个普通的求值参数(即会先计算参数值再使用)。
此函数的主要用途是作为「定义或修改函数的语法结构」的底层子程序,例如 defun(定义函数)或 advice-add(see 为 Emacs Lisp 函数添加建议)。您也可以通过它为符号赋予「非函数类型」的函数定义,比如键盘宏(see 键盘宏):
;; Define a named keyboard macro.
(fset 'kill-two-lines "\^u2\^k")
⇒ "\^u2\^k"
如果您想通过 fset 为某个函数创建别名,建议改用 defalias 函数。See Definition of defalias。
若操作后形成的函数定义链出现循环引用,Emacs 会抛出 cyclic-function-indirection(函数间接引用循环)错误。
正如 Scoping 变量绑定的作用域规则 中所说明的,Emacs 可以选择性地启用变量的词法绑定。当开启词法绑定时,你创建的任何命名函数(例如通过 defun),以及通过 lambda 宏、function 特殊形式或 #' 语法创建的任意匿名函数(see 匿名函数),都会被自动转换成一个 闭包(closure)。
闭包是一种携带了其定义时所处词法环境记录的函数。当它被调用时,其定义内部对词法变量的所有引用,都会使用这份被保留下来的词法环境。在其他所有方面,闭包的行为都与普通函数非常相似;特别地,它们可以用与普通函数完全相同的方式被调用。
关于闭包的使用示例,see 词法绑定。
目前,一个 Emacs Lisp 闭包对象以列表形式表示:符号 closure 作为第一个元素,表示词法环境的列表作为第二个元素,剩下的元素则是参数列表与函数体形式:
;; lexical binding is enabled.
(lambda (x) (* x x))
⇒ #f(lambda (x) [t] (* x x))
但是,闭包的内部结构对 Lisp 环境暴露这一事实,仅被视为内部实现细节。因此,我们不建议直接查看或修改闭包对象的结构。
传统上,函数是不透明对象,除了被调用之外,不提供其他功能。(Emacs Lisp 函数并非完全不透明,因为你可以从中提取一些信息,例如文档字符串、参数列表或交互规范,但它们在很大程度上仍然是不透明的。)这通常是我们所需要的,但偶尔我们需要函数对外暴露更多关于自身的信息。
开放式闭包(Open closures),简称 OClosures,是一类携带额外类型信息、并以槽位(slots)形式暴露自身部分信息的函数对象,你可以通过访问器函数来读取这些槽位。
开放式闭包的定义分为两步:首先使用 oclosure-define,通过指定该类型开放式闭包所包含的槽位,来定义一种新的 OClosure 类型;然后使用 oclosure-lambda 创建指定类型的 OClosure 对象。
假设我们想要定义键盘宏 —— 即能重新执行一系列按键事件的交互式函数(see 键盘宏)。你可以通过普通函数实现,示例如下:
(defun kbd-macro (key-sequence)
(lambda (&optional arg)
(interactive "P")
(execute-kbd-macro key-sequence arg)))
但通过这种方式定义的函数,你无法便捷地从中提取出 key-sequence(按键序列)—— 比如要打印这个序列时就会遇到困难。
我们可以通过开放式闭包解决这个问题,具体步骤如下。首先定义我们的键盘宏类型(同时我们决定为该类型新增一个 counter 槽位):
(oclosure-define kbd-macro "Keyboard macro." keys (counter :mutable t))
完成类型定义后,我们即可重写 kbd-macro 函数:
(defun kbd-macro (key-sequence)
(oclosure-lambda (kbd-macro (keys key-sequence) (counter 0))
(&optional arg)
(interactive "P")
(execute-kbd-macro keys arg)
(setq counter (1+ counter))))
可以看到,开放式闭包的 keys 和 counter 槽位,能作为局部变量在该开放式闭包的函数体内部访问。同时,我们现在也能从函数体外部访问这些槽位 —— 例如,用于描述一个键盘宏:
(defun describe-kbd-macro (km)
(if (not (eq 'kbd-macro (oclosure-type km)))
(message "Not a keyboard macro")
(let ((keys (kbd-macro--keys km))
(counter (kbd-macro--counter km)))
(message "Keys=%S, called %d times" keys counter))))
其中 kbd-macro--keys 和 kbd-macro--counter 是oclosure-define 宏为类型为 kbd-macro 的开放式闭包自动生成的访问器函数。
该宏用于定义一种新的开放式闭包(OClosure)类型,同时为其slots(槽位)生成对应的访问器函数。oname 可以是一个符号(即该新类型的名称),也可以是形如
(oname . type-props)
的列表 —— 这种情况下,type-props 是该开放式闭包类型的额外属性列表。slots 是一组槽位描述的列表,其中每个槽位可以是一个符号(即槽位名称),也可以是形如
(slot-name . slot-props)
的结构,其中 slot-props 是对应槽位 slot-name 的属性列表。
由 type-props 指定的开放式闭包类型属性可包含以下内容:
(:predicate pred-name)该属性要求创建一个名为 pred-name 的断言函数(predicate function)。此函数将用于识别类型为 oname 的开放式闭包(OClosure)。若未指定该类型属性,oclosure-define 会为这个断言函数生成一个默认名称。
(:parent otype)该属性将开放式闭包类型 otype 设置为类型 oname 的父类型。类型为 oname 的开放式闭包会继承其父类型定义的所有 slots(槽位)。
(:copier copier-name copier-args)该属性会触发一个「函数式更新函数」的定义(这类函数也被称为 复制器(copier))。该函数接收一个类型为 oname 的开放式闭包作为第一个参数,返回该闭包的副本 —— 副本中名为 copier-args 的槽位会被修改,取值为调用 copier-name 时传入的对应参数值。
对于 slots 中的每一个槽位,oclosure-define 宏都会创建一个名为 oname--slot-name 的访问器函数;这些函数可用于读取对应槽位的值。slots 中的槽位定义可指定该槽位的以下属性:
:mutable val默认情况下,槽位是不可变的;但如果为 :mutable 属性指定非 nil 的值,该槽位将变为可修改状态,例如可通过 setf 函数修改(see setf 宏)。
:type val-type该属性用于指定槽位中预期存储的值的类型。
该宏用于创建一个类型为 type 的匿名开放式闭包(OClosure),且该类型必须已通过 oclosure-define 定义完成。slots 应为一个列表,其元素格式为 (slot-name expr)。运行时,每个 expr(表达式)会按顺序求值,随后创建开放式闭包,并将这些求值结果初始化到对应的槽位中。
当该宏创建的开放式闭包以函数形式被调用时(see 调用函数),它会按照 arglist(参数列表)接收参数,并执行 body(函数体)中的代码。body 内可直接引用任意槽位的值,就像引用通过静态作用域捕获的局部变量一样。
若 object 是一个开放式闭包(OClosure),该函数会返回其开放式闭包类型(一个符号);否则返回 nil。
另一个与开放式闭包相关的函数是 oclosure-interactive-form,它允许部分类型的开放式闭包动态计算其交互形式(interactive form)。See oclosure-interactive-form。
当你需要修改其他库中定义的函数,或需要修改类似 foo-function 这样的钩子、进程过滤器(process filter),抑或是任何存储函数值的变量 / 对象字段时,你可以使用对应的设置函数:例如,对命名函数使用 fset 或 defun,对钩子变量使用 setq,对进程过滤器使用 set-process-filter——但这些方式通常过于「粗暴」,会直接丢弃原有值。
建议(advice) 特性允许你通过 为函数添加建议(advising the function) 的方式,在函数现有定义的基础上进行扩展。相比重新定义整个函数,这是一种更优雅的方法。
Emacs 的建议(advice)系统为此提供了两套原语:一套核心原语,用于处理存储在变量和对象字段中的函数值(对应的核心原语为 add-function 和 remove-function);另一套构建在核心原语之上的扩展原语,专门用于命名函数(主要原语为 advice-add 和 advice-remove)。
举一个简单的例子,以下代码展示了如何添加一段建议,让某个函数每次被调用时,其返回值都会被修改:
(defun my-double (x) (* x 2)) (defun my-increase (x) (+ x 1)) (advice-add 'my-double :filter-return #'my-increase)
添加这段建议后,若你调用 my-double 并传入参数 ‘3’,函数的返回值将变为 ‘7’。要移除这段建议,只需执行:
(advice-remove 'my-double #'my-increase)
一个更进阶的示例是追踪进程 proc 的进程过滤器调用情况:
(defun my-tracing-function (proc string) (message "Proc %S received %S" proc string)) (add-function :before (process-filter proc) #'my-tracing-function)
这会让该进程的输出在传递给原始进程过滤器之前,先传递给 my-tracing-function。my-tracing-function 会接收与原始函数完全相同的参数。当你不再需要追踪时,可通过以下代码恢复到无追踪的状态:
(remove-function (process-filter proc) #'my-tracing-function)
类似地,如果你想追踪名为 display-buffer 的函数的执行过程,可以使用:
(defun his-tracing-function (orig-fun &rest args)
(message "display-buffer called with args %S" args)
(let ((res (apply orig-fun args)))
(message "display-buffer returned %S" res)
res))
(advice-add 'display-buffer :around #'his-tracing-function)
此时,his-tracing-function 会替代原始函数被调用;该函数除了接收原始函数的参数外,还会将原始函数本身作为参数接收 ——因此它可以在需要时调用原始函数。当你不想再看到这些输出信息时,可通过以下代码恢复到无追踪的状态:
(advice-remove 'display-buffer #'his-tracing-function)
上述示例中使用的参数 :before 和 :around,用于指定两个函数的组合方式(因为函数组合的实现方式有很多种)。这个被添加的函数也被称为一段 建议(advice)。
该宏用于便捷地将建议函数 function 添加到存储在 place 中的函数上(see 广义变量)。
where 用于指定 function 与已有函数的组合方式,例如是在原函数之前执行,还是之后执行。两种函数的可用组合方式列表,see 建议的组合方式。
当修改一个变量(变量名通常以 -function 结尾)时,你可以指定 function 是全局生效,还是仅在当前缓冲区生效:
如果 place 只是一个符号,那么 function 会被添加到 place 的全局值上。
如果 place 是 (local symbol) 形式(其中 symbol 是返回变量名的表达式),
则 function 仅在当前缓冲区生效。
最后,如果你要修改词法变量,则需要使用 (var variable)。
通过 add-function 添加的每个函数,都可以附带一个属性关联列表 props。目前其中只有两个属性具有特殊含义:
name为这段建议(advice)指定一个名称,remove-function 可通过该名称识别要移除的函数。通常在 function 是匿名函数时使用。
depth用于指定当存在多段建议时,这些建议的执行顺序。默认深度为 0。深度为 100 表示这段建议应尽量放在最内层;深度为 −100 表示它应放在最外层。如果两段建议的深度相同,后添加的那段会位于外层。
对于 :before 类型的建议:
位于最外层表示它会最先执行,在其他所有建议之前;
位于最内层表示它刚好在原函数之前执行,与原函数之间没有其他建议。
对于 :after 类型的建议:
位于最内层表示它刚好在原函数之后执行,中间无其他建议;
位于最外层表示它会在最后执行,在所有其他建议之后。
对于 :override 类型的建议:
最内层的建议只会覆盖原函数,其他建议仍会对它生效;
最外层的建议不仅会覆盖原函数,还会覆盖所有其他已应用的建议。
若 function 非交互式函数,则组合后的函数会继承原函数的交互式规范(若原函数有定义);反之,组合后的函数会成为交互式函数,并使用 function 的交互式规范。有一个例外情况:如果 function 的交互式规范是一个函数(即 lambda 表达式或已定义的符号(fbound),而非普通表达式或字符串),那么组合函数的交互式规范会表现为调用该函数,并将原函数的交互式规范作为唯一参数传入。如需解析作为参数接收的这份规范,可使用 advice-eval-interactive-spec 函数。
注意:function 的交互式规范会作用于组合后的函数,因此它应遵循组合函数的调用约定,而非 function 自身的调用约定。在多数场景下这两者并无差异(因为调用约定完全相同),但对于 :around、:filter-args 和 :filter-return 类型的建议而言,这一点至关重要 —— 因为这些场景下 function 接收的参数,与存储在 place 中的原函数参数并不相同。
该宏用于将 function 从存储在 place 中的函数上移除。此操作仅在 function 是通过 add-function 添加到 place 时有效。
function 会通过 equal 函数与添加到 place 中的函数进行比较,以确保该逻辑对 lambda 表达式也能生效。此外,还会与添加到 place 的函数的 name 属性做比对 —— 这种方式比用 equal 比较 lambda 表达式更可靠。
若 advice 已存在于 function-def 中,则返回非 nil 值。与上文的 remove-function 类似,这里的 advice 不必是实际的函数,也可以是该段建议(advice)的 name 名称。
对所有添加到 function-def 中的建议片段,依次调用函数 f。调用 f 时会传入两个参数:建议函数本身,以及该建议的属性列表。
按照「带有该交互式规范的函数被交互式调用」的规则来解析 spec,并返回由此构建的参数列表。例如,(advice-eval-interactive-spec "r\nP")会返回一个包含三个元素的列表,其中包含选区的边界值和当前的前缀参数。
例如,如果你想让 C-x m(compose-mail)命令提示输入 ‘From:’ 邮件头,可以这样写:
(defun my-compose-mail-advice (orig &rest args)
"Read From: address interactively."
(interactive
(lambda (spec)
(let* ((user-mail-address
(completing-read "From: "
'("[email protected]"
"[email protected]")))
(from (message-make-from user-full-name
user-mail-address))
(spec (advice-eval-interactive-spec spec)))
;; Put the From header into the OTHER-HEADERS argument.
(push (cons 'From from) (nth 2 spec))
spec)))
(apply orig args))
(advice-add 'compose-mail :around #'my-compose-mail-advice)
建议(advice)的一个常见用途是作用于命名函数与宏。你可以直接像下面这样使用 add-function:
(add-function :around (symbol-function 'fun) #'his-tracing-function)
但对此你应该改用 advice-add 和 advice-remove。这套专门用于操作命名函数上附加建议的函数,相比 add-function 提供了以下额外特性:它们能正确处理宏和自动加载函数,能让 describe-function 保留原始文档字符串并同时记录附加的建议,还允许你在函数尚未定义时就提前添加或移除建议。
advice-add 适用于在不重新定义整个函数的前提下,修改现有函数被调用时的行为。但它也可能成为 bug 的来源,因为调用该函数的原有代码可能会假设函数保持旧有行为,一旦行为被建议修改,就可能运行出错。如果调试者没有注意到或忘记该函数已被建议修改,建议机制还会给调试带来困惑。
需要注意的是,这些问题并非源于建议机制本身,而是源于修改命名函数这一行为。如果通过 fset、defalias 或 cl-letf 这类底层原语来修改命名函数,问题会更加严重。从这个角度来看,使用建议是修改命名函数的更好方式,因为它会记录所有修改,便于查看与撤销。
修改命名函数应当只用于没有其他办法改变 Emacs 行为的场景。如果可以通过钩子(hook)实现相同效果,优先使用钩子(see 钩子)。如果你只是想修改某个按键的功能,更好的做法通常是:编写一个新命令,并将旧命令的按键绑定重映射到新命令上(see 命令重映射)。
如果你在编写供他人使用的发布代码,请尽量避免在其中使用建议。如果你想添加建议的函数没有对应的钩子来完成需求,请与 Emacs 开发者沟通,添加合适的钩子。特别注意:Emacs 自身的源码不应对内置函数添加建议。(这一惯例目前存在少数例外,但我们计划逐步修正。)通常来说,更清晰的做法是:在 foo 中创建一个新钩子,然后让 bar 使用这个钩子,而不是让 bar 为 foo 添加建议。
特殊形式(see 特殊形式)无法被添加建议,但宏可以像函数一样被添加建议。当然,这不会影响已经完成宏展开的代码,因此你需要确保建议在宏展开之前就已安装。
尽管可以为原语(see 什么是函数?)添加建议,但通常不建议这样做,原因有二:其一,部分原语会被建议机制自身调用,为它们添加建议可能导致无限递归;其二,许多原语会被 C 代码直接调用,而这类调用会忽略建议 —— 最终会出现一种混乱的情况:有些调用(来自 Lisp 代码)会遵循建议,而另一些调用(来自 C 代码)则不会。
该宏用于定义一段建议,并将其添加到名为 symbol 的函数上。若 name 为非 nil 值,这段建议会被命名为 symbol@name,且会以 name 作为标识安装;否则,该建议为匿名建议。其他参数的说明参见 advice-add。
将建议函数 function 添加到命名函数 symbol 上。其中 where 和 props 的含义与 add-function 中一致(see 操作建议的原语)。
从命名函数 symbol 中移除建议函数 function。function 也可以是某段建议的 name(名称)。交互式调用时,会分别提示输入已添加建议的函数 function 以及要移除的建议。
如果建议函数 function 已经存在于命名函数 symbol 中,则返回非 nil。function 也可以是某段建议的 name(名称)。
对添加到命名函数 symbol 上的每一段建议,都调用一次 function。调用 function 时会传入两个参数:建议函数本身及其属性列表。
以下是 add-function 和 advice-add 中参数 where 可使用的各种取值,用于指定建议函数与原函数的组合方式。
:before在原函数执行之前调用 function。两个函数接收相同的参数,组合后的函数返回值为原函数的返回值。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (apply function r) (apply oldfun r))
对于「单函数钩子」场景,(add-function :before funvar function)的效果类似于普通钩子中 (add-hook 'hookvar function) 的效果。
:after在原函数执行之后调用 function。两个函数接收相同的参数,组合后的函数返回值为原函数的返回值。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (prog1 (apply oldfun r) (apply function r)))
对于「单函数钩子」场景,(add-function :after funvar function)的效果类似于普通钩子中 (add-hook 'hookvar function 'append) 的效果。
:overrideThis completely replaces the old function with the new one. The old function
can of course be recovered if you later call remove-function.
:around调用 function 以替代原函数执行,但会将原函数作为额外参数传入 function。这是灵活性最高的组合方式:例如,你可以让原函数接收不同的参数、多次调用原函数、在 let 绑定环境中调用原函数,也可以选择有时将任务委托给原函数执行,有时则完全覆盖原函数的逻辑。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (apply function oldfun r))
:before-while在原函数执行前调用 function;若 function 返回 nil,则不再调用原函数。两个函数接收相同的参数,组合后的函数返回值为原函数的返回值(若原函数未执行,则返回 nil)。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (and (apply function r) (apply oldfun r)))
对于单函数钩子场景,(add-function :before-while funvar function) 的效果,等同于当 hookvar 通过 run-hook-with-args-until-failure 执行时,调用 (add-hook 'hookvar function) 的效果。
:before-until在原函数之前调用 function,并且只有当 function 返回 nil 时,才调用原函数。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (or (apply function r) (apply oldfun r)))
对于单函数钩子,(add-function :before-until funvar function)等价于在 hookvar 通过 run-hook-with-args-until-success 运行时,使用 (add-hook 'hookvar function) 的效果。
:after-while在原函数之后调用 function,并且只有当原函数返回非 nil 时才调用。两个函数接收相同的参数,组合后的返回值是 function 的返回值。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (and (apply oldfun r) (apply function r)))
对于单函数钩子,(add-function :after-while funvar function)等价于在 hookvar 通过 run-hook-with-args-until-failure 运行时,使用 (add-hook 'hookvar function 'append) 的效果。
:after-until在原函数之后调用 function,并且只有当原函数返回 nil 时才调用。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (or (apply oldfun r) (apply function r)))
(add-function :after-until funvar function)对于单函数钩子场景,其效果等同于:当 hookvar 通过run-hook-with-args-until-success 执行时,调用(add-hook 'hookvar function 'append) 的效果。
:filter-args先调用 function,并将其返回结果(需为列表类型)作为新参数传递给原函数。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (apply oldfun (funcall function r)))
:filter-return先调用原函数,再将其返回结果传递给 function。更具体地说,这两个函数的组合行为等价于:
(lambda (&rest r) (funcall function (apply oldfun r)))
大量代码使用旧版的 defadvice 机制,而该机制已被新的 advice-add 废弃。新接口的实现与语义都要简单得多。
一段旧版 advice 示例如下:
(defadvice previous-line (before next-line-at-end
(&optional arg try-vscroll))
"Insert an empty line when moving up from the top line."
(if (and next-line-add-newlines (= arg 1)
(save-excursion (beginning-of-line) (bobp)))
(progn
(beginning-of-line)
(newline))))
可以将其在新版 advice 机制中转换为一个普通函数:
(defun previous-line--next-line-at-end (&optional arg try-vscroll)
"Insert an empty line when moving up from the top line."
(if (and next-line-add-newlines (= arg 1)
(save-excursion (beginning-of-line) (bobp)))
(progn
(beginning-of-line)
(newline))))
显然,这并不会实际修改 previous-line 函数。要实现修改,旧版 advice 还需要执行以下操作:
(ad-activate 'previous-line)
whereas the new advice mechanism needs:
(advice-add 'previous-line :before #'previous-line--next-line-at-end)
需要注意的是,ad-activate 具有全局作用:它会激活为指定函数启用的所有 advice 片段。如果你只想激活或停用某一个特定的片段,就需要通过 ad-enable-advice 和 ad-disable-advice 来 启用(enable) 或 停用(disable) 该片段。而新版机制则取消了这种区分。
如下所示的环绕型(Around)advice:
(defadvice foo (around foo-around)
"Ignore case in `foo'."
(let ((case-fold-search t))
ad-do-it))
(ad-activate 'foo)
可转换为:
(defun foo--foo-around (orig-fun &rest args)
"Ignore case in `foo'."
(let ((case-fold-search t))
(apply orig-fun args)))
(advice-add 'foo :around #'foo--foo-around)
关于 advice 的 类型(class),需要注意:新版的 :before 与旧版的 before 并不完全等价。因为在旧版 advice 中,你可以修改函数的参数(例如通过 ad-set-arg),这会影响原函数看到的参数值;而在新版 :before 中,在 advice 里通过 setq 修改参数,不会对原函数看到的参数产生任何影响。
在移植依赖这种行为的 before advice 时,你需要将其改为新版的 :around 或 :filter-args advice。
同样,旧版的 after advice 可以通过修改 ad-return-value 来改变返回值,而新版的 :after advice 无法做到这一点。因此在移植这类旧版 after advice 时,你需要将其改为新版的 :around 或 :filter-return advice。
并非所有函数都能被可靠地增强(advice)。字节编译器可能会选择将某个函数调用替换为一串指令序列,而不再调用你想要修改的那个函数。
这通常由以下三种机制之一造成:
byte-compile 属性如果一个函数的符号具有 byte-compile 属性,字节编译器会使用该属性,而不是符号本身的函数定义。See 字节编译函数。
byte-optimize 属性如果一个函数的符号具有 byte-optimize 属性,字节编译器可能会重写函数参数,或者直接选择使用另一个完全不同的函数。
compiler-macro 声明形式一个函数可以在其定义中包含特殊的 compiler-macro declare 声明形式(see declare 形式),它会定义一个 展开器(expander),在编译该函数时被调用。该展开器可能会导致最终生成的字节码不再调用原函数。
你可以将一个具名函数标记为 废弃(obsolete) 状态,这意味着该函数可能会在未来的某个版本中被移除。当 Emacs 对包含该函数的代码进行字节编译时,或是在显示该函数的文档时,都会发出该函数已废弃的警告。除此之外,废弃函数的其他行为与普通函数完全一致。
将函数标记为废弃最简便的方式,是在函数的 defun 定义中加入 (declare (obsolete …)) 形式的声明。See declare 形式。你也可以使用下文所述的 make-obsolete 函数来实现该功能。
宏(see 宏)也可通过 make-obsolete 标记为废弃状态,其效果与标记函数废弃完全相同。函数或宏的别名同样可以被标记为废弃;这种情况下,被标记为废弃的是别名本身,而非该别名指向的函数或宏。
该函数将 obsolete-name 标记为废弃状态。obsolete-name 应为一个符号,代表某个函数、宏,或是函数 / 宏的别名。
若 current-name 为符号,则警告信息会提示使用 current-name 替代 obsolete-name。current-name 无需是 obsolete-name 的别名,也可以是功能相近的另一个函数。current-name 也可为字符串,此时该字符串将直接作为警告信息使用。该信息应以小写字母开头,并以句点结尾;它也可以设为 nil,这种情况下警告信息不会包含任何额外说明。
参数 when 应为字符串类型,用于指明该函数首次被标记为废弃的时间 —— 例如某个日期或版本号。
这个便捷宏会将函数 obsolete-name 标记为废弃状态,同时将其定义为函数 current-name 的别名。该宏等价于以下代码:
(defalias obsolete-name current-name doc) (make-obsolete obsolete-name current-name when)
此外,你还可以将某个函数特定的调用方式标记为废弃:
该函数将参数列表 signature 声明为调用 function 的正确形式。这样一来,只要 Emacs 字节编译器遇到以其他方式调用 function 的 Emacs Lisp 代码,就会发出警告(但仍然允许这段代码完成字节编译)。when 应为字符串,用于指明该调用方式首次被标记为废弃的时间(通常是版本号字符串)。
例如,在旧版 Emacs 中,sit-for 函数接受三个参数,形式如下:
(sit-for seconds milliseconds nodisp)
在过渡阶段,该函数仍然支持这三个参数,但会像下面这样将旧的调用方式声明为已弃用:
(set-advertised-calling-convention 'sit-for '(seconds &optional nodisp) "22.1")
该函数的替代方案是使用 advertised-calling-convention 类型的 declare 声明规范,详见 declare 形式。
内联函数(inline function) 的行为与普通函数完全一致,仅存在一处差异:当你对该函数的调用进行字节编译时(see 字节编译),函数的定义会被直接展开到调用处。
定义内联函数的简便方式,是将定义时的 defun 替换为 defsubst。定义的其余部分保持不变,而使用 defsubst 会指定该函数在字节编译时以内联方式处理。
该宏用于定义内联函数。其语法与 defun 完全相同(see 定义函数)。
将函数设为内联通常能提升函数调用的执行速度,但也存在缺点。其一,它会降低灵活性:如果你修改了函数的定义,已被内联的调用仍会使用旧定义,除非重新编译这些调用代码。
另一个缺点是,将大型函数设为内联会增大编译后代码在文件和内存中的体积。由于内联函数的速度优势在小型函数上体现得最为明显,因此通常不应该将大型函数设为内联。
此外,内联函数在调试、跟踪和 advice 增强(see 为 Emacs Lisp 函数添加建议)方面表现不佳。由于便于调试和可灵活重定义函数是 Emacs 的重要特性,因此即使函数很小,你也不应该将其设为内联,除非其执行速度确实至关重要,并且你已经通过计时测试确认使用 defun 确实存在性能问题。
内联函数定义之后,可以在同一个文件的后续位置对其执行内联展开,就像宏一样。
可以使用 defmacro 定义一个宏,使其展开为与内联函数执行时完全相同的代码(see 宏)。但宏只能在表达式中直接使用 —— 宏不能通过 apply、mapcar 等方式调用。此外,将普通函数转换为宏需要一定的工作量。而将其转换为内联函数则很简单:只需把 defun 替换成 defsubst。由于内联函数的每个参数都只会被精确求值一次,你不必像使用宏那样担心函数体中会多次使用参数。
作为另一种方案,你可以通过提供一段代码来定义函数,让字节编译器将其作为编译器宏进行内联展开(see declare 形式)。下面这些宏可以实现这一点。
该宏通过提供一段实现内联展开的代码(作为编译器宏)来定义函数 name。该函数将接受参数列表 args,并执行指定的函数体 body。
若提供了 doc,则其应为该函数的文档字符串(see 函数的文档字符串);若提供了 declare,则其应为一个 declare 形式的声明(see declare 形式),用于指定函数的元数据。
通过 define-inline 定义的函数,相比通过 defsubst 或 defmacro 定义的宏,具有以下多个优势:
mapcar 使用(see 映射函数)。
cl-defsubst 更可预测(see Argument Lists in Common Lisp Extensions for GNU Emacs Lisp)。
与 defmacro 类似,使用 define-inline 定义的内联函数,其作用域规则(动态作用域或词法作用域)继承自调用位置。See Scoping 变量绑定的作用域规则。
下面这些宏应当在由 define-inline 定义的函数体中使用。
为 define-inline 引用 expression。其作用类似于反引号(see 反引号),但只用于引用代码,且只接受 ,,不接受 ,@。
该宏提供了一种便捷方式,用于确保内联函数的参数只被精确求值一次,同时也用于创建局部变量。
它与 let 类似(see 局部变量):按照 bindings 的指定创建局部变量,然后在这些绑定生效的情况下执行 body。
bindings 中的每个元素可以是一个符号,或是形如 (var expr) 的列表;效果是对 expr 求值,并将 var 绑定到该结果。但当 bindings 中的元素只是一个符号 var 时,会将对 var 求值后的结果重新绑定给 var 自身(这与 let 的行为截然不同)。
bindings 的末尾部分可以是 nil,也可以是一个用于存放参数列表的符号;若是后者,则会对每个参数求值,并将该符号绑定到求值后的参数列表。
若 expression 的值已是已知状态,则返回非 nil 值。
返回 expression 的值。
触发错误,并根据 format 格式化 args 参数列表。
以下是使用 define-inline 的示例:
(define-inline myaccessor (obj)
(inline-letevals (obj)
(inline-quote (if (foo-p ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))))
这段代码等价于
(defsubst myaccessor (obj) (if (foo-p obj) (aref (cdr obj) 3) (aref obj 2)))
declare 形式 ¶declare 是一个特殊宏,可用于为函数或宏添加元属性:例如,将其标记为废弃,或在 Emacs Lisp 模式中为其形式指定特殊的 TAB 缩进规则。
该宏会忽略参数并求值为 nil,它没有运行时效果。但是,当 declare 形式出现在 defun、defsubst 函数定义(see 定义函数)或 defmacro 宏定义(see 定义宏)的 declare 参数中时,它会将 specs 指定的属性附加到该函数或宏上。这项工作由 defun、defsubst 和 defmacro 专门完成。
specs 中的每个元素都应具有形式 (property args…),且不应该被引用。它们具有如下作用:
(advertised-calling-convention signature when) ¶其效果等价于调用 set-advertised-calling-convention(see 声明函数为废弃状态)。signature 指定调用该函数或宏的正确参数列表,when 应为一个字符串,指明旧参数列表从何时起被标记为废弃。
(debug edebug-form-spec)仅对宏有效。使用 Edebug 单步执行宏时,将使用 edebug-form-spec。See 宏调用插桩。
(doc-string n)用于定义那些自身会用来定义函数、宏、变量等实体的函数或宏。它指明第 n 个参数(如果存在)应被视为文档字符串。
(indent indent-spec)按照 indent-spec 对该函数或宏的调用进行缩进。通常用于宏,但也适用于函数。See 宏的缩进。
(interactive-only value)将函数的 interactive-only 属性设为 value。See The interactive-only property。
(obsolete current-name when) ¶将函数或宏标记为废弃,效果类似于调用 make-obsolete(see 声明函数为废弃状态)。current-name 可以是:
一个符号(此时警告信息会提示改用该符号);
一个字符串(直接作为警告信息);
或 nil(此时警告信息不提供额外说明)。
when 应为字符串,指明该函数或宏首次被标记为废弃的时间。
(compiler-macro expander) ¶仅可用于函数,告知编译器将 expander 用作优化函数。当遇到形如 (function args…) 的函数调用时,宏展开器会以该表达式以及 args… 为参数调用 expander。expander 可以返回一个新表达式以替换原函数调用,也可以直接返回原表达式,表示不修改该函数调用。
当 expander 是 lambda 形式时,它应当只带一个参数(即形如 (lambda (arg) body)),因为该函数的形式参数会由系统自动添加到 lambda 的参数列表中。
(gv-expander expander)声明 expander 为用于将该宏(或函数)的调用作为广义变量处理的函数,作用与 gv-define-expander 类似。expander 可以是一个符号,也可以是形如 (lambda (arg) body) 的形式,此时该函数还能访问宏(或函数)的参数。
(gv-setter setter)声明 setter 为用于将该宏(或函数)的调用作为广义变量处理的设置函数。若 setter 是符号,则会被传给 gv-define-simple-setter;它也可以是形如 (lambda (arg) body) 的形式,此时该函数能访问宏(或函数)的参数,并会被传给 gv-define-setter。
(completion completion-predicate)声明 completion-predicate 为一个判断函数,用于决定在 M-x 补全时,是否将某个函数的符号加入函数列表。该判断函数仅当 read-extended-command-predicate 被自定义为 command-completion-default-include-p 时才会被调用;默认情况下 read-extended-command-predicate 的值为 nil(see execute-extended-command)。判断函数 completion-predicate 会被传入两个参数:函数的符号与当前缓冲区。
(modes modes)指明该命令仅适用于指定的 modes(主模式)。See 为命令指定适用模式。
(interactive-args arg ...)指定需要为 repeat-command 保存的参数。每个 arg 的形式为 argument-name form。
(pure val)若 val 为非 nil,则该函数为 纯函数(pure)(see 什么是函数?)。这与函数符号的 pure 属性作用相同(see 标准符号属性)。
(side-effect-free val)若 val 为非 nil,则该函数无副作用,因此字节编译器可以忽略那些不使用返回值的调用。这与函数符号的 side-effect-free 属性作用相同,see 标准符号属性。
(important-return-value val)若 val 为非 nil,字节编译器会对不使用该函数返回值的调用发出警告。这与函数符号的 important-return-value 属性作用相同,see 标准符号属性。
(speed n)指定该函数在本地编译时生效的 native-comp-speed 值(see 本地编译变量)。这允许在函数级别控制为该函数生成本地代码时使用的优化级别。特别地,如果 n 为 −1,该函数的本地编译将只生成字节码,而非本地机器码。
(safety n)指定该函数生效的 compilation-safety 值。这允许在函数级别控制为该函数生成代码时使用的安全级别(see 本地编译变量)。
(ftype type &optional function) ¶将 type 声明为该函数的类型。该类型会被 describe-function 用于文档展示,并被本地编译器(see Lisp 本地代码编译)用于代码优化与类型推导。错误的类型声明可能导致本地编译后的代码崩溃(见下文)。带有类型声明的函数在 C-h C-f 中会显示为拥有 声明类型(declared type),与之相对,无声明的函数则显示 推导类型(inferred type)。
type 是一个 类型说明符(type specifier)(see 类型说明符),形式为:(function (arg-1-type … arg-n-type) RETURN-TYPE)。参数类型中可以穿插 &optional 和 &rest,以反映函数的调用规范(see 参数列表的特性)。
如果存在 function,它应当是正在定义的函数的名称。
下面是在 declare 中使用 ftype 定义函数 positive-p 的示例:该函数接受一个 number 类型的参数,并返回一个 boolean 类型的值。
(defun positive-p (x)
(declare (ftype (function (number) boolean)))
(when (> x 0)
t))
类似地,下面定义了一个函数 cons-or-number:它的第一个参数类型为 cons 或 number,第二个是 string 类型的可选参数,并返回符号 is-cons 或 is-number 中的一个:
(defun cons-or-number (x &optional err-msg)
(declare (ftype (function ((or cons number) &optional string)
(member is-cons is-number))))
(if (consp x)
'is-cons
(if (numberp x)
'is-number
(error (or err-msg "Unexpected input")))))
有关更多类型的说明,参见 Lisp 数据类型。
使用错误的类型声明函数会导致未定义行为。如果这样的函数在本地编译时将 compilation-safety 设置为 0(see compilation-safety),则可能在加载编译后的代码时出现执行错误,甚至导致 Emacs 崩溃。对已声明类型的函数进行重定义或 advice 增强时,必须保留原有的签名,以避免此类问题。
no-font-lock-keyword仅对宏有效。带有该声明的宏在字体高亮(see Font Lock Mode)下会像普通函数一样高亮,而不会被特殊标记为宏。
对文件进行字节编译时,经常会产生关于编译器未知函数的警告(see 编译器错误)。有时这确实代表一个问题,但更多时候,相关函数是定义在其他文件中,代码运行时会被加载。例如,编译 simple.el 时曾经会出现这样的警告:
simple.el:8727:1:Warning: the function ‘shell-mode’ is not known to be
defined.
实际上,shell-mode 仅在一个函数中被使用,该函数会在调用 shell-mode 之前执行 (require 'shell),因此 shell-mode 在运行时会被正确定义。当你确定这类警告并非真正的问题时,最好将其抑制 —— 这能让那些可能代表真实问题的新警告更容易被发现。你可以通过 declare-function 来实现这一点。
只需在相关函数的第一次使用之前添加一条 declare-function 语句即可:
(declare-function shell-mode "shell" ())
该语句表明 shell-mode 定义在 shell.el 文件中(后缀 ‘.el’ 可省略)。编译器会默认该文件确实定义了这个函数,而不会进行检查。
可选的第三个参数用于指定 shell-mode 的参数列表。本例中,该函数不接受任何参数(注意 nil 与不指定值是不同的)。在其他情况下,参数列表可能形如 (file &optional overwrite)。你并非必须指定参数列表,但如果指定了,字节编译器就能检查函数调用是否与声明的参数列表匹配。
告知字节编译器,假定 function 定义在文件 file 中。可选的第三个参数 arglist 有两种取值:
若为 t,表示未指定该函数的参数列表;
若为列表,则是与 defun 风格一致的形式参数列表(需包含外层括号)。
若省略 arglist,其默认值为 t 而非 nil—— 这是省略参数时的特殊行为,意味着如果要传入第四个参数但不传入第三个,必须将第三个参数占位符指定为 t(而非通常使用的 nil)。可选的第四个参数 fileonly 若为非 nil 值,则仅检查 file 文件是否存在,不验证该文件中是否实际定义了 function。
若要验证这些函数是否确实声明在 declare-function 所指定的位置,可使用 check-declare-file 检查单个源码文件中所有 declare-function 调用的有效性,或使用 check-declare-directory 检查指定目录及其子目录下所有文件的相关声明。
这些命令会通过 locate-library 查找理应包含函数定义的文件;若该函数未找到对应文件,则会以包含 declare-function 调用的文件所在目录为基准,展开函数定义文件的路径。
你也可以通过指定后缀为 ‘.c’ 或 ‘.m’ 的文件名,声明某个函数为原生函数(primitive)。这种用法仅适用于调用那些仅在特定系统中定义的原生函数场景 —— 大多数原生函数是全局定义的,因此不会触发此类警告。
有时某个文件会可选地使用来自外部包的函数。如果你在 declare-function 语句中的文件名前加上前缀 ‘ext:’,那么工具会在文件存在时进行检查,若不存在则直接跳过,不报错。
有一些函数定义是 ‘check-declare’ 无法识别的(例如 defstruct 以及其他一些宏)。在这种情况下,你可以给 declare-function 传入一个非 nil 的 fileonly 参数,表示只检查文件是否存在,不验证它是否真的定义了该函数。注意,如果你想这样做又不必指定参数列表,应当把 arglist 参数设为 t(因为 nil 表示空参数列表,而非 “未指定”)。
某些主模式(例如 SES)会调用存储在用户文件中的函数。(关于 SES 的更多信息,see Simple Emacs Spreadsheet。)用户文件的来源往往不可靠 —— 你可能从刚认识的人那里得到一个表格文件,或是通过邮件从陌生人手中获取。因此,在确认安全之前,直接调用源代码保存在用户文件中的函数是有风险的。
若 form 是一个 安全的(safe) Lisp 表达式,则返回 nil;若表达式可能存在安全风险,则返回一个描述风险原因的列表。参数 unsafep-vars 是一个符号列表,代表当前上下文已知的、拥有临时绑定的符号;该参数主要用于函数内部的递归调用。当前缓冲区是一个隐式参数,会提供缓冲区本地绑定的列表。
unsafep 函数的设计原则是快速且简洁,因此仅会执行非常浅层的分析,这导致它会判定许多实际安全的 Lisp 表达式为 “不安全”。目前尚未发现 unsafep 对不安全表达式返回 nil 的情况。但需要注意:一个本身安全的 Lisp 表达式,可能返回带有 display 属性的字符串 ——该属性中可包含关联的 Lisp 表达式,且这部分表达式会在字符串插入缓冲区后执行。这类关联表达式可能具有恶意。为保证安全,你必须在将用户代码计算得到的所有字符串插入缓冲区之前,删除其中的所有属性。
这里列出了一些与函数调用和函数定义相关的函数一览表。它们的详细说明在其他章节,我们在此提供交叉引用。
applySee 调用函数.
autoloadSee 自动加载.
call-interactivelySee 交互式调用.
called-interactively-pSee 区分交互式调用.
commandpSee 交互式调用.
documentationSee 访问文档字符串.
evalSee 求值.
funcallSee 调用函数.
functionSee 匿名函数.
ignoreSee 调用函数.
indirect-functionSee 符号函数间接引用.
interactiveSee 使用 interactive.
interactive-pSee 区分交互式调用.
mapatomsSee 创建与编入符号.
mapcarSee 映射函数.
map-char-tableSee 字符表.
mapconcatSee 映射函数.
undefinedSee 按键查找函数.
宏(Macros) 让你可以定义新的控制结构以及其他语言特性。宏的定义方式与函数非常相似,但它并非说明如何计算一个值,而是说明如何生成另一段 Lisp 表达式,再由这段表达式去计算出最终的值。我们把这段生成的表达式称为宏的 展开式(expansion)。
宏之所以能做到这一点,是因为它作用于未求值的参数表达式,而不像函数那样直接处理参数的值。因此,宏可以用这些参数表达式(或其中一部分)来构造展开式。
如果你只是为了提升运行速度,想用宏去实现普通函数就能完成的功能,建议改用内联函数。See 内联函数。
假设我们想要定义一个 Lisp 结构来递增变量的值,效果类似于 C 语言中的 ++ 运算符。我们希望编写 (inc x) 就能实现 (setq x (1+ x)) 的效果。以下是实现该功能的宏定义:
(defmacro inc (var) (list 'setq var (list '1+ var)))
当以 (inc x) 调用该宏时,参数 var 是符号 x——而非 函数调用时那样取 x 的值。宏的体部利用这个符号构造出展开式,也就是 (setq x (1+ x))。宏定义返回这个展开式后,Lisp 会接着对其求值,从而完成 x 的递增操作。
这个谓词函数用于检测其参数是否为宏:如果是,返回 t;否则返回 nil。
宏调用在形式上与函数调用完全相同:都是以宏的名称开头的列表,列表中的其余元素即为宏的参数。
宏调用的求值过程与函数调用类似,但有一个关键区别:宏的参数就是宏调用中直接写出的表达式本身,在传递给宏定义之前不会被求值。与之相对,函数的参数是函数调用列表中各元素求值后的结果。
获取参数后,Lisp 会像调用函数一样执行宏定义。宏的参数变量会绑定到宏调用中的参数(若是 &rest 参数,则绑定到参数列表),宏体的执行与返回值的方式也与函数体一致。
宏与函数的第二个关键区别在于:宏体返回的值是另一段 Lisp 表达式,也就是该宏的 展开式(expansion)。Lisp 解释器在从宏得到这段展开式后,会立刻对其进行正常求值。
由于展开式会按常规方式被求值,因此它内部可以包含对其他宏的调用,甚至可以是对同一个宏的递归调用(尽管这种情况并不常见)。
需要说明的是,Emacs 在加载未编译的Lisp 文件时会尝试展开宏。这一操作并非总能实现,但如果成功,会提升后续代码的执行速度。See 程序的加载方式。
你可以通过调用 macroexpand 函数来查看指定宏调用的展开式。
若 form 是一个宏调用,该函数会对其进行展开。如果展开结果仍是另一个宏调用,则会继续展开,直到得到一个非宏调用的表达式为止。这个最终表达式即为 macroexpand 的返回值。若 form本身并非宏调用,则会按原样返回。
需要注意的是,macroexpand 不会处理 form 的子表达式(不过部分宏定义可能会主动处理)。即便这些子表达式本身是宏调用,macroexpand 也不会对其展开。
macroexpand 函数不会展开对内联函数的调用。通常也无需这么做,因为内联函数调用的可读性与普通函数调用无异。
若提供了 environment 参数,它会指定一个宏定义关联列表(alist),该列表中的宏定义会覆盖当前已定义的宏。字节编译功能会用到这一特性。
(defmacro inc (var)
(list 'setq var (list '1+ var)))
(macroexpand '(inc r))
⇒ (setq r (1+ r))
(defmacro inc2 (var1 var2)
(list 'progn (list 'inc var1) (list 'inc var2)))
(macroexpand '(inc2 r s))
⇒ (progn (inc r) (inc s)) ; inc not expanded here.
macroexpand-all 与 macroexpand 一样会展开宏,但它会查找并展开 form 中所有的宏(而非仅展开顶层宏)。如果没有任何宏被展开,返回值会与 form 满足 eq 相等性。
沿用前文 macroexpand 的示例,改用 macroexpand-all 执行时可以看到:macroexpand-all 确实会展开内嵌的 inc 调用:
(macroexpand-all '(inc2 r s))
⇒ (progn (setq r (1+ r)) (setq s (1+ s)))
该函数与 macroexpand 一样会展开宏,但仅执行一步展开操作:若展开结果仍是另一个宏调用,macroexpand-1 不会继续展开它。
你可能会问:为何我们要大费周章地先为宏计算出展开式,再对展开式求值?为何不让宏体直接生成期望的结果?这背后的原因与编译机制有关。
当待编译的 Lisp 程序中出现宏调用时,Lisp 编译器会像解释器一样调用该宏的定义,并得到对应的展开式。但编译器并不会直接求值这个展开式,而是将其当作直接写在程序里的代码来编译。最终,编译后的代码既能实现宏预期的返回值和副作用,又能以编译代码的完整速度执行。如果让宏体自身直接计算返回值和副作用,这一机制就无法生效 —— 因为这些计算会在编译阶段完成,而这通常没有实际意义。
要让宏调用的编译正常工作,在编译这些宏调用时,对应的宏必须已在 Lisp 中完成定义。编译器提供了一项特殊功能来协助实现这一点:若待编译的文件中包含 defmacro 形式,该宏会被临时定义,并在该文件后续的编译过程中生效。
对文件进行字节编译时,还会执行文件中顶层的所有 require 调用。因此,你可以通过加载(require)定义宏的文件,确保编译期间能获取到必要的宏定义(see 功能)。为了避免他人运行编译后的程序时加载这些宏定义文件,可将 require 调用包裹在 eval-when-compile 中(see 编译时求值)。
Lisp 宏对象是一个列表:其 CAR 部分为符号 macro,CDR 部分是一个函数。宏的展开过程,本质是将该函数(通过 apply 调用)作用于宏调用中 未求值 的参数列表。
我们可以像使用匿名函数一样使用匿名 Lisp 宏,但这种做法从未被实际采用—— 因为将匿名宏传递给 mapcar 这类函数式工具毫无意义。在实际应用中,所有 Lisp 宏都有名称,且几乎总是通过 defmacro 宏来定义。
defmacro 会将符号 name(无需加引号)定义为如下形式的宏:
(macro lambda args . body)
(注意:该列表的 CDR 部分是一个 lambda 表达式。)这个宏对象会被存储到 name 的函数单元(function cell)中。args 的含义与函数参数完全一致,且可使用 &rest 和 &optional 关键字(see 参数列表的特性)。name 和 args 均无需加引号。defmacro 的返回值未定义。
若存在 doc 参数,其值应为一个字符串,用于指定该宏的文档字符串(documentation string)。若存在 declare 参数,其值应为一个 declare 形式,用于指定宏的元数据(see declare 形式)。需注意,宏不支持交互式声明(interactive declarations),因为宏无法以交互方式调用。
宏常常需要结合常量和非常量部分来构造复杂的列表结构。为简化这一操作,可使用 ‘`’ 语法(see 反引号)。例如:
(defmacro t-becomes-nil (variable)
`(if (eq ,variable t)
(setq ,variable nil)))
(t-becomes-nil foo)
≡ (if (eq foo t) (setq foo nil))
宏展开可能会产生违背直觉的结果。本节将介绍一些可能引发问题的重要情况,以及避免这些问题需遵循的规则。
编写宏时最常见的问题,就是过早执行了实际工作 — 在宏展开阶段就执行,而不是把执行逻辑放在展开后的代码里。例如,某个实际的软件包曾有这样一个错误的宏定义:
(defmacro my-set-buffer-multibyte (arg)
(if (fboundp 'set-buffer-multibyte)
(set-buffer-multibyte arg)))
使用这个错误的宏定义,程序在解释执行时正常,但编译后就会出错。原因是:这个宏会在编译期间调用 set-buffer-multibyte,这是错误的;而编译后的程序在运行时,这段代码却什么都不做。
程序员真正想要的定义应该是这样:
(defmacro my-set-buffer-multibyte (arg)
(if (fboundp 'set-buffer-multibyte)
`(set-buffer-multibyte ,arg)))
在条件满足时,这个宏会展开成对 set-buffer-multibyte 的调用,而这个调用会在编译后的程序实际运行时才执行。
定义宏时,必须留意参数在展开代码执行时会被求值多少次。下面这个用于简化循环的宏示例,就展示了这类问题。该宏可以让我们写出类似 for 循环的结构。
(defmacro for (var from init to final do &rest body)
"Execute a simple \"for\" loop.
For example, (for i from 1 to 10 do (print i))."
(list 'let (list (list var init))
(cons 'while
(cons (list '<= var final)
(append body (list (list 'inc var)))))))
(for i from 1 to 3 do (setq square (* i i)) (princ (format "\n%d %d" i square))) →
(let ((i 1))
(while (<= i 3)
(setq square (* i i))
(princ (format "\n%d %d" i square))
(inc i)))
⊣1 1
⊣2 4
⊣3 9
⇒ nil
该宏中的 from、to 和 do 参数仅作为语法糖(syntactic sugar) 存在 —— 它们会被完全忽略。设计思路是让你在宏调用的这些位置写入这类 “无实际作用的辅助词”(例如 from、to、do),仅用于提升代码可读性。
以下是使用反引号简化后的等效定义:
(defmacro for (var from init to final do &rest body)
"Execute a simple \"for\" loop.
For example, (for i from 1 to 10 do (print i))."
`(let ((,var ,init))
(while (<= ,var ,final)
,@body
(inc ,var))))
该定义的两种写法(使用反引号和不使用反引号)都存在一个缺陷:final 会在每次循环迭代时都被求值。若 final 是常量,这不会有问题;但如果它是更复杂的表达式(例如 (long-complex-calculation x)),则会显著降低执行速度;若 final 带有副作用,多次执行它很可能导致逻辑错误。
一个设计良好的宏定义会主动规避这类问题:生成的展开式会确保参数表达式仅被求值一次(除非重复求值是该宏的设计意图)。以下是 for 宏的正确展开版本:
(let ((i 1)
(max 3))
(while (<= i max)
(setq square (* i i))
(princ (format "%d %d" i square))
(inc i)))
以下是能生成该展开式的宏定义:
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
`(let ((,var ,init)
(max ,final))
(while (<= ,var max)
,@body
(inc ,var))))
遗憾的是,这一修复方案引入了另一个问题,具体将在下一节说明。
在上一节中,我们对 for 的定义做了如下修正,以确保展开式对宏参数的求值次数符合预期:
(defmacro for (var from init to final do &rest body) "Execute a simple for loop: (for i from 1 to 10 do (print i))."
`(let ((,var ,init)
(max ,final))
(while (<= ,var max)
,@body
(inc ,var))))
for 宏的新定义引入了一个新问题:它创建了一个名为 max 的局部变量,而这是用户完全没有预料到的。这会导致如下示例中的异常行为:
(let ((max 0))
(for x from 0 to 10 do
(let ((this (frob x)))
(if (< max this)
(setq max this)))))
for 宏体内部对 max 的引用,本应指向用户定义的 max 绑定,实际却访问到了 for 宏创建的 max 绑定。
修正该问题的方法是使用未注册符号(uninterned symbol) 替代 max(see 创建与编入符号)。未注册符号的绑定和引用方式与普通符号完全一致,但由于它是由 for 宏动态创建的,我们可以确定它不会出现在用户的代码中。同时,因为未注册符号未被录入符号表,用户后续也无法在代码中手动使用它 —— 除了 for 宏主动插入的位置外,该符号不会出现在任何其他地方。以下是采用该方案的 for 宏定义:
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar (make-symbol "max")))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(inc ,var)))))
这样会创建一个名为 max 的未注册符号,并将其用于展开式中,而不是使用普通表达式里那种已注册的符号 max。
如果宏定义本身会对宏参数表达式进行求值(例如调用 eval),就可能引发另一个问题(see 求值)。你必须考虑到:宏展开可能远早于代码实际运行,而调用者的上下文(宏展开式最终会在其中运行)此时还不可用。
此外,如果你的宏定义没有使用 lexical-binding(词法绑定),它的形参可能会遮蔽用户代码中的同名变量。在宏体内部,宏参数的绑定是该变量最内层的局部绑定,因此被求值表达式内部对该名称的任何引用,都会指向这个宏参数。示例如下:
(defmacro foo (a) (list 'setq (eval a) t))
(setq x 'b)
(foo x) → (setq b t)
⇒ t ; and b has been set.
;; but
(setq a 'c)
(foo a) → (setq a t)
⇒ t ; but this set a, not c.
用户代码中的变量是叫 a 还是 x,结果会完全不同,因为 a 会与宏的参数变量 a 发生冲突。
另外,上面的 (foo x) 在代码被编译时,展开结果会不一样,甚至直接报错。原因是:编译时 (foo x) 就会被展开,而 (setq x 'b) 要等到程序真正运行时才会执行。
要避免这类问题,不要在计算宏展开的过程中对参数表达式求值。正确的做法是:把表达式代入到宏展开式中,让它的值在执行展开后代码时才计算。本章的其他示例都是这么做的。
有时候会出现这样的问题:在解释执行的函数里,宏调用每次被求值时都会重新展开;而在编译后的函数里,宏只会在编译阶段展开一次。如果宏定义本身带有副作用,执行效果就会因为展开次数不同而不一致。 因此,你应该避免在计算宏展开的过程中产生副作用,除非你非常清楚自己在做什么。
有一种特殊的 “副作用” 是无法避免的:构造 Lisp 对象。几乎所有宏展开都会构造列表,这也是大多数宏存在的意义。这通常是安全的,只有一种情况需要格外小心:当你构造的对象会成为宏展开式中被引用常量(quoted constant) 的一部分时。
如果宏只在编译时被展开一次,那么对应的对象也只会在编译期间被构造一次。但在解释执行时,宏每次被调用都会重新展开,这意味着每次都会构造一个新对象。
在大多数规范的 Lisp 代码中,这种差异并不会产生影响。只有当你对宏构造出来的对象执行副作用操作时,才会引发问题。因此,为避免麻烦,请避免对宏定义所构造的对象施加副作用。下面这个例子展示了这类副作用是如何引发问题的:
(defmacro empty-object () (list 'quote (cons nil nil)))
(defun initialize (condition)
(let ((object (empty-object)))
(if condition
(setcar object condition))
object))
如果 initialize 是解释执行的,那么每次调用它时,都会新建一个列表 (nil)。因此,多次调用之间不会保留副作用。如果 initialize 是编译执行的,那么宏 empty-object 会在编译时就展开,生成一个常量 (nil);之后每次调用 initialize,都会复用并修改这个同一个对象。
避免出现这类极端问题的一种思路是:把 empty-object 看成一种特殊常量,而不是用来分配内存的结构。你不会对 '(nil) 这样的常量使用 setcar,自然也不应该对 (empty-object) 使用它。
在宏定义中,你可以使用 declare 形式(see 定义宏)来指定按下 TAB 时,该宏的调用该如何缩进。缩进说明的写法如下:
(declare (indent indent-spec))
这样做会在宏名上设置 lisp-indent-function 属性。
indent-spec 可以取以下几种值:
nil此值等同于未设置该属性 — 使用标准缩进格式。
defun将该宏当作 ‘def’ 类结构处理:把第二行视为体部(body) 的起始位置。
宏的前 number 个参数为 特殊(distinguished) 参数;其余参数被视作表达式的体部。表达式内某行的缩进方式,取决于该行第一个参数是否为特殊参数:
若该参数属于体部,该行缩进比包含此表达式的左括号多 lisp-body-indent 列;
若该参数是特殊参数,且为第一个或第二个参数,则该行缩进比左括号多 两倍 的 lisp-body-indent 列;
若该参数是特殊参数,但非第一个 / 第二个参数,则使用标准缩进格式。
symbol 需为一个函数名;缩进时会调用该函数计算表达式内对应行的缩进值。 该函数接收两个参数:
待缩进行的起始位置。
parse-partial-sexp(用于计算缩进和嵌套层级的 Lisp 原语函数)解析至该行起始位置时返回的值。
该函数应当返回以下两种结果之一: 一个数字,表示当前行的缩进列数; 或者一个列表,其 car 部分为上述数字。 返回数字与返回列表的区别在于:返回数字表示同一嵌套层级下后续所有行都应按此行的方式缩进;返回列表则表示后续行可能需要不同的缩进。 这在由 C-M-q 计算缩进时会产生影响:如果返回值是数字,C-M-q 在到达列表末尾之前,无需重新计算后续行的缩进。
Emacs 用户可以使用自定义(Customize)界面来定制变量和面孔,无需编写 Lisp 代码。See Easy Customization in The GNU Emacs Manual。本章介绍如何 定义自定义项(customization items),用户可通过自定义界面对这些项目进行交互设置。
自定义项包括:可定制变量,使用
defcustom 宏;
可定制外观,使用 defface 定义(在 Defining Faces 中单独说明);
以及 自定义组(customization groups),使用
defgroup,
它们充当相关自定义项的分组容器。
接下来几节将要介绍的自定义声明 — defcustom、defgroup 等 — 都接受关键字参数(see 永不改变的变量),用于指定各类信息。本节描述适用于所有类型自定义声明的关键字。
除 :tag 外,所有这些关键字在同一个项中都可以多次使用,每次使用效果相互独立。:tag 是个例外,因为同一个项只能显示一个名称。
:tag label ¶在自定义菜单和缓冲区中,使用字符串 label(而非项本身的名称)作为该项的标签。不要使用与项的真实名称差异过大的标签,否则会造成混淆。
:group group ¶将该自定义项加入到组 group 中。如果自定义项缺少此关键字,则会被放入当前文件中最后定义的组。
在 defgroup 中使用 :group 时,会将新组设为 group 的子组。
如果多次使用该关键字,可以将同一个项放入多个组。显示其中任意一个组时都会出现该项。请不要过度使用此功能,否则会造成使用上的困扰。
:link link-data ¶在该项的文档字符串后添加一个外部链接。这是一段带有按钮的文字,可跳转至其他相关文档。
link-data 支持以下几种写法:
(custom-manual info-node)链接到某个 Info 节点;info-node 是一个字符串,用于指定节点名称,例如 "(emacs)Top"。该链接在自定义缓冲区中显示为 ‘[Manual]’,点击后会打开内置的 Info 阅读器并跳转到对应节点。
(info-link info-node)作用与 custom-manual 相同,区别是该链接在自定义缓冲区中直接显示 Info 节点名称。
(url-link url)链接到某个网页;url 是表示网址的字符串 URL。该链接在自定义缓冲区中显示为 url,点击后会调用由 browse-url-browser-function 指定的网页浏览器打开。
(emacs-commentary-link library)链接到某个库的注释说明部分;library 是表示库名的字符串。See Conventional Headers for Emacs Libraries。
(emacs-library-link library)链接到某个 Emacs Lisp 库文件;library 是表示库名的字符串。
(file-link file)链接到某个文件;file 是表示文件名的字符串。用户激活该链接时,会通过 find-file 打开对应文件。
(function-link function)链接到函数的文档;function 是一个字符串,指定函数名。用户点击该链接时,会通过 describe-function 显示该函数的说明。
(variable-link variable)链接到变量的文档;variable 是一个字符串,指定变量名。用户点击该链接时,会通过 describe-variable 显示该变量的说明。
(face-link face)链接到外观(face)的文档;face 是一个字符串,指定外观名称。用户点击该链接时,会通过 describe-face 显示该外观的说明。
(custom-group-link group)链接到另一个自定义组。激活该链接会为 group 创建一个新的自定义缓冲区。
你可以在 link-data 的第一个元素后面添加 :tag name,来指定在自定义缓冲区中显示的文字。例如:(info-link :tag "foo" "(emacs)Top") 会生成一个指向 Emacs 手册的链接,在缓冲区中显示为 ‘foo’。
你可以多次使用该关键字,以添加多个链接。
:load file ¶在显示该自定义项之前,加载文件 file(字符串)(see 加载)。加载通过 load 完成,且仅在文件尚未加载时执行。
:require feature ¶当你保存的自定义设置设置该项的值时,执行 (require 'feature)。feature 应为一个符号。
使用 :require 最常见的场景是:某个变量用于启用某个功能(如次要模式),而如果未加载实现该模式的代码,仅仅设置变量不会产生任何效果。
:version version ¶该关键字用于指定:该项是在 Emacs 版本 version 中首次引入的,或其默认值在该版本中被修改。version 必须为字符串。
:package-version '(package . version) ¶该关键字用于指定:该项是在 package 的 version 版本中首次引入的,或其含义、默认值在该版本中被修改。该关键字的优先级高于 :version。
package 应为软件包的官方名称(符号形式,例如 MH-E)。version 应为字符串。如果软件包 package 是作为 Emacs 的一部分发布的,那么 package 和 version必须出现在 customize-package-emacs-version-alist 的值中。
作为 Emacs 一部分分发、且使用了 :package-version 关键字的软件包,必须同时更新 customize-package-emacs-version-alist 变量。
这个关联列表(alist)提供了 Emacs 版本 与 :package-version 关键字中记录的软件包版本之间的映射关系。其元素格式如下:
(package (pversion . eversion)...)
每个作为符号的 package,都对应一个或多个子元素,每个子元素包含一个软件包版本 pversion 以及与之关联的 Emacs 版本 eversion。这些版本均为字符串。例如,MH-E 软件包通过以下形式更新该关联列表:
(add-to-list 'customize-package-emacs-version-alist
'(MH-E ("6.0" . "22.1") ("6.1" . "22.1") ("7.0" . "22.1")
("7.1" . "22.1") ("7.2" . "22.1") ("7.3" . "22.1")
("7.4" . "22.1") ("8.0" . "22.1")))
package 的值必须唯一,并且需要与 :package-version 关键字中的 package 值保持一致。由于用户可能在错误信息中看到该值,因此建议使用软件包的官方名称,例如 MH-E 或 Gnus。
每个 Emacs Lisp 软件包都应拥有一个主自定义组,用于包含该包中的所有选项、面孔和其他子组。如果软件包的选项和面孔数量较少,只需创建一个组并将所有内容放入其中即可。当选项和面孔数量超过二十个左右时,应当将它们组织为多个子组,并把这些子组放在软件包的主自定义组下。也可以将部分选项和面孔与子组并列,直接放在主组中。
软件包的主组(或唯一组)应当隶属于一个或多个标准自定义组。(如需查看完整列表,可使用 M-x customize。)选择其中一个或多个(但不要过多),并通过 :group 关键字将你定义的组加入这些标准组中。
声明新自定义组的方式是使用 defgroup。
将 group 声明为包含 members 的自定义组。符号 group 不需要加引号。参数 doc 为该组指定文档字符串。
参数 members 是一个列表,用于指定一组初始的自定义项作为该组的成员。但在绝大多数情况下,members 会设为 nil,你可以在定义各个成员时,通过 :group 关键字将它们加入该组。
如果你希望通过 members 直接指定组成员,那么每个元素的格式应为(name widget)。其中 name 是一个符号,widget 是用于编辑该符号的组件类型。常用的组件有:变量使用 custom-variable,面孔使用 custom-face,组使用 custom-group。
当你在 Emacs 中新增一个组时,只需在 defgroup 中使用 :version 关键字即可,该组下的各个成员无需再单独使用它。
除了通用关键字(see 通用项关键字)之外,你还可以在 defgroup 中使用以下关键字:
:prefix prefix ¶如果组中某个项的名称以 prefix 开头,并且可定制变量 custom-unlispify-remove-prefixes的值为非 nil,那么该项的显示标签将会省略 prefix。一个组可以设置任意多个前缀。
一个组所包含的变量、面孔和子组,都存储在该组符号的 custom-group 属性中。See 访问符号属性。该属性的值是一个点对列表,每个元素的 car 是变量、面孔或子组的符号,cdr 是对应的类型符号:custom-variable、custom-face 或 custom-group。
如果该变量的值为非 nil,那么当用户在自定义界面中设置该组时,由组的 :prefix 关键字指定的前缀将会从标签名称中省略。
该变量的默认值为 nil,即省略前缀的功能是关闭的。这是因为省略前缀常常会导致选项和面孔的名称变得令人困惑。
可自定义变量(Customizable variables)(也称为 用户选项(user options))是可以通过自定义界面设置值的全局 Lisp 变量。与使用 defvar 定义的普通全局变量不同(see 定义全局变量),可自定义变量使用 defcustom 宏定义。除了内部会调用 defvar 之外,defcustom 还会声明该变量在自定义界面中如何显示、允许取哪些值等信息。
该宏将 option 声明为用户选项(即可自定义变量)。不要给 option 加引号。
参数 standard 是一个表达式,用于指定 option 的标准默认值。执行 defcustom 时会对 standard 求值,但不一定会立即将选项绑定为该值:
如果 option 已有默认值,则保持不变;
如果用户已保存过该选项的自定义设置,则以用户自定义值作为默认值;
否则,将 standard 求值后的结果作为默认值。
与 defvar 类似,该宏会将 option 标记为特殊变量,表示它始终使用动态绑定。如果 option 已处于词法绑定中,该词法绑定会持续到绑定结构结束为止。See Scoping 变量绑定的作用域规则。
standard 表达式还可能在其他时刻被求值 — 只要自定义系统需要知道 option 的标准默认值就会执行。因此请确保使用一个随时重复求值都不会产生副作用的表达式。
参数 doc 为该变量指定文档字符串。
如果某个 defcustom 未指定 :group,则会使用同一文件中最后一个用 defgroup 定义的组。这样一来,大多数 defcustom 都不需要显式写明 :group。
在 Emacs Lisp 模式下,当你使用快捷键 C-M-x(即 eval-defun)对一个 defcustom 形式进行求值时,eval-defun 的一项特殊机制会无条件地设置该变量,而不会检查变量的值是否为空。(该机制同样适用于 defvar,see 定义全局变量。)对已定义过的 defcustom 使用 eval-defun,如果存在 :set 函数(见下文),则会调用该函数。
如果你将 defcustom 写在 Emacs 预加载的 Elisp 文件中(see Building Emacs),在转储(dump)阶段设置的标准值可能不正确 —— 例如,因为它所依赖的其他变量尚未被赋予正确的值。这种情况下,可以使用下文介绍的 custom-reevaluate-setting,在 Emacs 启动完成后重新计算标准值。
除了 通用项关键字 中列出的通用关键字外,本宏还支持以下关键字:
:type type将 type 作为该选项的数据类型。它规定了哪些值是合法的,以及如何显示该值(see 定制类型)。每个 defcustom 都应当为此关键字指定一个值。
:options value-list ¶指定该选项常用的合理值列表。用户并不受限于只能使用这些值,但这些值会作为便捷选项提供给用户。
该关键字仅对部分类型有效,目前包括 hook、plist 和 alist。有关如何使用 :options 的说明,请查看对应类型的定义。
使用不同的 :options 值重新求值 defcustom 形式时,不会清除之前求值所添加的值,也不会清除通过 custom-add-frequent-value(见下文)添加的值。
:set setfunction ¶指定 setfunction 作为在使用 Customize 界面时修改此选项值的方式。函数
setfunction 应接收两个参数:一个符号(选项名称)和新值,并且需要执行
为该选项正确更新值所需的所有操作(这未必意味着简单地将该选项设为 Lisp 变量);
不过,最好不要以破坏性方式修改其值参数。setfunction 的默认值为
set-default-toplevel-value。
若 setfunction 已定义,那么在 Emacs Lisp 模式下使用 C-M-x 求值
defcustom 形式时,以及通过 setopt 宏修改 option 的值时
(see setopt),该函数也会被调用。
如果指定了此关键字,该变量的文档字符串应说明如何在手写的 Lisp 代码中完成相同
操作——既可直接调用 setfunction,也可使用 setopt。
:get getfunction ¶指定 getfunction 作为提取此选项值的方式。函数 getfunction 应接收
一个参数(一个符号),并返回 Custom 应当用作该符号当前值的内容(该内容未必是
该符号的 Lisp 值)。其默认值为 default-toplevel-value。
要正确使用 :get,你必须真正理解 Custom 的工作机制。它适用于那些在
Custom 中被当作变量处理、但实际上并未存储在 Lisp 变量中的值。如果为一个
确实存储在 Lisp 变量中的值指定 getfunction,几乎可以肯定是错误的。
:initialize function ¶function 应当是一个在 defcustom 被求值时用于初始化变量的函数。它应接收两个参数:选项名称(一个符号)和值。下面是一些供此用途使用的预定义函数:
custom-initialize-set使用该变量的 :set 函数初始化变量,但如果变量已经非空,则不再重新初始化。
custom-initialize-default与 custom-initialize-set 类似,但使用 set-default-toplevel-value来设置变量,而非该变量自身的 :set 函数。这通常是那些 :set 函数用于启用或禁用次要模式(minor mode)的变量的常用选择;使用此选项时,定义变量不会调用次要模式函数,但通过 Customize 定制变量时会调用。
custom-initialize-reset始终使用 :set 函数初始化变量。如果变量已经非空,则通过 :get 方法获取当前值,再调用 :set 函数将其重置。这是 :initialize 的默认函数。
custom-initialize-changed如果变量已经被设置或被定制过,则使用 :set 函数初始化变量;否则,直接使用 set-default-toplevel-value。
custom-initialize-delay行为与 custom-initialize-set 类似,但会将实际初始化延迟到下一次 Emacs 启动时。此函数应在预加载的文件中(或用于自动加载的变量)使用,以便初始化在运行时上下文而非构建时上下文中完成。它还有一个副作用:延迟后的初始化会通过 :set 函数执行。See Building Emacs。
:local value ¶若 value 为 t,则将 option 标记为自动缓冲区局部变量;若值为 permanent,则同时将 option 的 permanent-local 属性设为 t。See 创建与删除缓冲区局部绑定。
:risky value ¶将该变量的 risky-local-variable 属性设为 value。See 文件局部变量。
:safe function ¶将该变量的 safe-local-variable 属性设为 function。See 文件局部变量。
:set-after variables ¶在根据保存的定制设置变量时,确保先设置 variables 列出的变量,再设置本变量;即,延迟设置本变量,直到其他变量处理完毕。如果本变量必须依赖其他变量已设置为预期值才能正常工作,可使用 :set-after。
为用于开启某项功能的选项指定 :require 关键字会很有用。这会使得每当该选项被设置时,若对应功能尚未加载,Emacs 就会加载它。See 通用项关键字。示例如下:
(defcustom frobnicate-automatically nil "Non-nil means automatically frobnicate all buffers." :type 'boolean :require 'frobnicate-mode :group 'frobnicate)
若某个定制项的类型(如 hook(钩子)或 alist(关联列表))支持 :options 关键字,则你可以通过调用 custom-add-frequent-value,在 defcustom 声明外部为该类型的取值列表添加额外值。例如,如果你定义了一个函数 my-lisp-mode-initialization,打算从 emacs-lisp-mode-hook 中调用它,你可能希望将该函数添加到 emacs-lisp-mode-hook 的合理取值列表中,但又不想编辑其原始定义。你可以这样做:
(custom-add-frequent-value 'emacs-lisp-mode-hook 'my-lisp-mode-initialization)
针对定制选项 symbol(符号),将 value(值)添加到其合理取值列表中。
添加值的具体效果取决于 symbol 的定制类型。
由于求值 defcustom 形式时不会清除之前添加的值,因此 Lisp 程序可通过该函数,为尚未定义的用户选项添加取值。
在内部实现中,defcustom 会使用以下符号属性:standard-value 用于记录标准值对应的表达式,saved-value 用于记录用户通过定制缓冲区保存的值,customized-value 用于记录用户通过定制缓冲区设置、但未保存的值。See 符号属性。此外,还有 themed-value,用于记录由主题设置的值(see 自定义主题)。这些属性均为列表类型,其首个元素(car)是一个可求值为对应值的表达式。
该函数会重新求 symbol(符号)的标准值 ——symbol 应为通过 defcustom 声明的用户选项。若该变量已被定制过,则此函数会改为重新求其已保存值(saved value)。随后,函数会将该用户选项设置为这个重新求得的值(若选项定义了 :set 属性,则会使用该属性对应的函数完成设置)。
此函数适用于那些「在其值能被正确计算之前就已定义」的可定制选项。例如,Emacs 启动过程中,会对部分在预加载 Emacs Lisp 文件中定义、但初始值依赖仅在运行时可用信息的用户选项,调用该函数。
若 arg 是可定制变量,该函数返回非 nil 值。可定制变量需满足以下任一条件:
拥有 standard-value 或 custom-autoload 属性的变量
(通常意味着该变量由 defcustom 声明);或是另一个可定制变量的别名。
使用 defcustom 定义用户选项时,必须指定其 定制类型(customization type)。定制类型是一个 Lisp 对象,它描述了两点:(1) 该选项的合法取值范围;(2) 在定制缓冲区中如何显示并编辑该选项的值。
在 defcustom 中,通过 :type 关键字指定定制类型。:type 的参数会被求值,但仅在 defcustom 执行时求值一次,因此让该值动态变化并无实际意义。通常我们会使用带引用的常量,例如:
(defcustom diff-command "diff" "The command to use to run diff." :type '(string) :group 'diff)
一般来说,定制类型是一个列表,其第一个元素是一个符号,即后续章节中定义的某一个定制类型名称。在该符号之后,可以根据符号的含义跟随若干个参数。在类型符号与其参数之间,你还可以可选地写入「关键字‑值」对(see 类型关键字)。
有些类型符号不使用任何参数,这类符号被称为 简单类型(simple types)。对于简单类型,如果你不使用任何「关键字‑值」对,可以省略包围类型符号的括号。例如,直接将 string 作为定制类型,等价于 (string)。
所有定制类型均以部件(widget)的形式实现;更多参见 Introduction in The Emacs Widget Library
本节描述所有简单的自定义类型。对于其中的几种自定义类型,自定义界面会提供 输入完成功能,对应的快捷键为 C-M-i 或 M-TAB。
sexp该值可以是任何可以打印并读回的 Lisp 对象。如果你不想花时间去定义一个更具体
的类型,就可以将 sexp 作为任何选项的备用类型。
integer值必须为整数。
natnum值必须为非负整数。
number值必须为数字(浮点型或整型)。
float值必须为浮点型。
string值必须为字符串。自定义界面会在缓冲区中显示该字符串,且不会显示分隔用的 ‘"’ 字符或反斜杠 ‘\’ 转义符。
regexp与 string 类似,不同之处在于该字符串必须是有效的正则表达式。
character值必须为字符码。字符码实际上是一个整数,但此类型会通过在缓冲区中插入字符 来显示该值,而非直接显示其数字。
file值必须为文件名。界面会提供输入完成功能。
(file :must-match t)值必须为一个现有文件的文件名。界面会提供输入完成功能。
directory值必须是一个目录。界面组件提供补全功能。
hook值必须是一个函数列表。该自定义类型用于钩子变量。
你可以在钩子变量的 defcustom 中使用 :options 关键字,
指定推荐用于该钩子的函数列表;See 定义自定义变量。
symbol值必须是一个符号。它会以符号名的形式显示在自定义缓冲区中。 界面组件提供补全功能。
function值必须是 lambda 表达式或函数名。界面组件为函数名提供补全。
variable值必须是一个变量名。界面组件提供补全功能。
face值必须是一个代表 face 名称的符号。界面组件提供补全功能。
boolean值为布尔类型 — 即 nil 或 t。
注意,通过同时使用 choice 和 const(见下一节),
你不仅可以指定值必须为 nil 或 t,
还可以为每个值指定描述文本,使其贴合该选项的具体含义。
key值是符合 key-valid-p 检查的有效按键,
适用于例如 keymap-set 等函数。
key-sequence值是一个按键序列。自定义缓冲区使用与 kbd 函数相同的语法显示按键序列。
详见 See 按键序列。这是旧类型;请改用 key。
coding-system值必须是一个编码系统名称,可通过 M-TAB 进行补全。
color值必须是有效的颜色名称。界面组件会为颜色名称提供补全功能,同时还会显示颜色示例, 并提供一个按钮,可从 *Colors* 缓冲区中显示的颜色名称列表里选择颜色名。
fringe-bitmap值必须是有效的边缘位图(fringe bitmap)名称。界面组件提供补全功能。
当所有简单类型都不适用时,你可以使用复合类型——这类类型基于其他类型或指定数据 构建新类型。被指定的类型或数据称为复合类型的参数(arguments)。复合类型的标准格式如下:
(constructor arguments...)
你也可以在参数前添加“关键字-值”对,格式如下:
(constructor {keyword value}... arguments...)
下表列出了各类构造器,以及如何使用它们定义复合类型:
(cons car-type cdr-type)值必须是一个 cons 单元(cons cell),其 CAR 部分需符合 car-type 类型,
CDR 部分需符合 cdr-type 类型。例如,(cons string symbol)
是一种自定义类型,可匹配 ("foo" . foo) 这类值。
在自定义缓冲区中,CAR 和 CDR 会分别显示和编辑, 各自按照其指定的类型进行处理。
(list element-types…)值必须是一个列表,其元素个数与给出的 element-types 数量完全一致; 并且每个元素必须符合对应的 element-type 类型。
例如,(list integer string function) 描述了一个包含三个元素的列表;
第一个元素必须是整数,第二个是字符串,第三个是函数。
在自定义缓冲区中,每个元素会根据为其指定的类型分别显示和编辑。 The value must be a list with exactly as many elements as the
(group element-types…)用法与 list 类似,区别仅在于自定义缓冲区中文本的显示格式。
list 会为每个元素值加上标签;而 group 不会。
(vector element-types…)与 list 类似,区别是值必须是向量(vector)而不是列表。
元素的用法与 list 中相同。
(alist :key-type key-type :value-type value-type)值必须是一个由 cons 单元组成的列表,每个单元的 CAR 表示一个键, 其自定义类型为 key-type;同一个单元的 CDR 表示一个值, 其自定义类型为 value-type。 用户可以添加和删除键/值对,并编辑每一对的键和值。
如果省略,key-type 和 value-type 默认均为 sexp。
用户可以添加任何符合指定键类型的键,但你可以通过 :options
关键字指定某些键,使其得到优先显示(see 定义自定义变量)。
这些指定的键会始终显示在自定义缓冲区中(并附带合适的值),
并带有一个复选框,用于在关联列表中启用、禁用或排除该键/值对。
用户无法编辑由 :options 关键字参数指定的键。
:options 关键字的参数应该是一个列表,
列出关联列表中合理的键的说明。通常它们只是原子(atom),表示自身。例如:
:options '("foo" "bar" "baz")
该写法指定了三个已知的键,即 "foo"、"bar" 和 "baz",
这些键会始终优先显示。
你可能希望为特定键限制值类型,例如,与 "bar" 键关联的值只能是整数。
要实现这一点,可将列表中的原子替换为子列表:第一个元素仍像之前一样指定键,
第二个元素则指定该键对应的值类型。例如:
:options '("foo" ("bar" integer) "baz")
最后,你可能希望修改键的展示方式。默认情况下,
由于用户无法修改通过 :options 关键字指定的特殊键,
这些键会以 const 类型直接显示。但你可以为键指定更专用的展示类型——
比如若已知该键是绑定了函数的符号,可使用 function-item 类型。
实现方式是将键的符号替换为自定义类型规范:
:options '("foo"
((function-item some-function) integer)
"baz")
许多关联列表(alist)会使用双元素列表而非 cons 单元。例如:
(defcustom list-alist
'(("foo" 1) ("bar" 2) ("baz" 3))
"Each element is a list of the form (KEY VALUE).")
而非:
(defcustom cons-alist
'(("foo" . 1) ("bar" . 2) ("baz" . 3))
"Each element is a cons-cell (KEY . VALUE).")
由于列表是基于 cons 单元实现的,你可以将上述示例中的 list-alist
视作 cons 单元形式的关联列表(alist)——其中值类型是仅包含一个元素的列表,
该元素存储实际值。
(defcustom list-alist '(("foo" 1) ("bar" 2) ("baz" 3))
"Each element is a list of the form (KEY VALUE)."
:type '(alist :value-type (group integer)))
此处使用 group 界面组件而非 list,仅因为其显示格式更贴合该场景的需求。
同理,你可以通过这一技巧的变体,实现一个键关联多个值的关联列表:
(defcustom person-data '(("brian" 50 t)
("dorith" 55 nil)
("ken" 52 t))
"Alist of basic info about people.
Each element has the form (NAME AGE MALE-FLAG)."
:type '(alist :value-type (group integer boolean)))
(plist :key-type key-type :value-type value-type)该自定义类型与 alist(见上文)类似,但存在两点区别:
(i) 信息以属性列表(property list)的形式存储(see 属性列表);
(ii) 若省略 key-type,其默认值为 symbol 而非 sexp。
(choice alternative-types…)值必须符合 alternative-types 中的某一种类型。例如,
(choice integer string) 允许值为整数或字符串。
在自定义缓冲区中,用户可通过菜单选择其中一种类型, 随后按照该类型的常规方式编辑对应的值。
通常,此菜单中的字符串由选项自动决定;但你可以在备选类型中使用 :tag 关键字,
为菜单指定不同的显示文字。例如,若一个整数表示空格数量,而字符串表示直接使用的文本,
你可以这样编写自定义类型:
(choice (integer :tag "Number of spaces")
(string :tag "Literal text"))
这样菜单就会显示 ‘Number of spaces(空格数量)’ 和 ‘Literal text(原文文本)’。
对于 nil 不是有效值、且不是 const 类型的备选选项,
你应当使用 :value 关键字为其指定一个有效的默认值。See 类型关键字。
如果某个值可以匹配多个备选类型,自定义系统会选择第一个能匹配该值的类型。 这意味着你应当将最具体的类型放在前面,最通用的类型放在最后。 下面是正确用法示例:
(choice (const :tag "Off" nil)
symbol (sexp :tag "Other"))
这样一来,特殊值 nil 就不会被当作普通符号处理,
符号也不会被当作普通 Lisp 表达式处理。
(radio element-types…) ¶与 choice 类似,区别在于选项以**单选按钮**而非菜单显示。
这样做的好处是,在适用时可以显示选项的说明文档,
因此常用于在多个常量函数(function-item 自定义类型)之间选择。
(const value)值必须是 value — 不允许其他任何值。
const 的主要用途是用在 choice 内部。例如,
(choice integer (const nil)) 允许值为整数或 nil。
:tag 经常与 const 配合,用在 choice 内部。
例如:
(choice (const :tag "Yes" t)
(const :tag "No" nil)
(const :tag "Ask" foo))
这段代码描述了一个变量:t 表示“是”,nil 表示“否”,
foo 表示 “询问(ask)”。
(other value)该备选选项可以匹配任意 Lisp 值,但如果用户选择此选项, 就会选用值 value。
other 的主要用途是作为 choice 的最后一个元素。
例如:
(choice (const :tag "Yes" t)
(const :tag "No" nil)
(other :tag "Ask" foo))
这段代码描述了一个变量:t 表示“是”,nil 表示“否”,
其他任何值都表示 “询问(ask)”。
如果用户从选项菜单中选择 ‘询问Ask’,就会设定值为 foo;
而任何其他值(非 t、非 nil、非 foo)
都会像 foo 一样显示为 ‘询问Ask’。
(function-item function)与 const 类似,但专用于表示函数类型的值。
它会同时显示函数名和文档字符串。
文档字符串可以是通过 :doc 指定的内容,
也可以是 function 自身自带的文档字符串。
(variable-item variable)与 const 类似,但专用于表示变量名类型的值。
它会同时显示变量名和文档字符串。
文档字符串可以是通过 :doc 指定的内容,
也可以是 variable 自身自带的文档字符串。
(set types…)值必须是一个列表,且列表中的每个元素必须匹配指定的 types 中的某一个。
它在自定义缓冲区中以复选清单的形式显示,
因此每个 types 最多只能对应一个元素,也可以没有。
不允许出现匹配同一类型的多个不同元素。
例如,(set integer symbol) 只允许列表中包含一个整数和/或一个符号;
不允许多个整数或多个符号。因此,在 set 中很少使用
integer 这类不具体的类型。
set 中的 types 绝大多数情况下都是 const 类型,如下例:
(set (const :bold) (const :italic))
有时它们用于描述关联列表(alist)中的可选元素:
(set (cons :tag "Height" (const height) integer)
(cons :tag "Width" (const width) integer))
这样就可以让用户 可选地 指定高度值和宽度值。
(repeat element-type)值必须是一个列表,且列表中的每个元素都必须符合 element-type 类型。 它在自定义缓冲区中显示为元素列表,带有 ‘[INS]’ 和 ‘[DEL]’ 按钮, 用于添加或删除元素。
(restricted-sexp :match-alternatives criteria) ¶这是最通用的复合类型构造器。 值可以是任何满足 criteria 中任一条件的 Lisp 对象。 criteria 必须是一个列表,其中每个元素可以是以下形式之一:
nil 或非 nil。
在列表中使用谓词意味着,
谓词返回非 nil 的对象都是可接受的值。
'object。
列表中的此类元素表示,object 本身就是可接受的值。
例如:
(restricted-sexp :match-alternatives
(integerp 't 'nil))
该写法允许整数、t 和 nil 作为合法值。
在自定义缓冲区中,所有合法值都会使用其读取语法(read syntax)显示, 用户可以通过文本方式编辑它们。
下面是复合类型中可用于关键字-值对的关键字列表:
:tag tag将 tag 用作此备选选项的名称,用于与用户交互。
对于出现在 choice 内部的类型,此关键字非常有用。
:match-alternatives criteria ¶使用 criteria 匹配可能的值。
该关键字仅在 restricted-sexp 中使用。
:args argument-list ¶将 argument-list 的元素用作该类型构造器的参数。
例如,(const :args (foo)) 等价于 (const foo)。
你很少需要显式编写 :args,
因为通常参数会被自动识别为最后一个关键字-值对之后的内容。
:inline 特性允许你将**可变数量**的元素**拼接**到 list 或 vector
自定义类型的中间。使用方法是:在包含于 list 或 vector 内部的
某个类型规范中添加 :inline t。
通常,list 或 vector 类型规范中的每一项都描述**单个**元素类型。
但当某一项包含 :inline t 时,它所匹配的值会**直接合并**到外层序列中。
例如,如果该项匹配一个包含三个元素的列表,这三个元素会直接成为整个序列的三个元素。
这类似于反引用结构中的 ‘,@’(see 反引号)。
例如,要指定一个列表,其第一个元素必须是 baz,
剩余参数可以是零个或多个 foo 和 bar,可使用如下自定义类型:
(list (const baz) (set :inline t (const foo) (const bar)))
它可以匹配如 (baz)、(baz foo)、(baz bar)
和 (baz foo bar) 这样的值。
当元素类型为 choice 时,:inline 不应写在 choice 本身,
而应写在 choice 的(部分)备选选项中。
例如,要匹配一个以文件名开头,后面紧跟符号 t 或两个字符串的列表,可使用:
(list file
(choice (const t)
(list :inline t string string)))
如果用户选择 choice 中的第一个备选项,则整个列表有两个元素,第二个元素是 t。
如果用户选择第二个备选项,则整个列表有三个元素,第二个和第三个必须是字符串。
界面组件可以通过 :match-inline 指定谓词,
用于判断一个内联值是否匹配该组件。
你可以在自定义类型的类型名符号之后,指定关键字—参数对。 下面是可用的关键字及其含义:
:value default提供默认值。
如果某个备选项中 nil 不是有效值,
那么必须使用 :value 指定一个合法的默认值。
如果你将它用于出现在 choice 内部的备选项类型,
它会指定:当用户在自定义缓冲区的菜单中选中该备选项时,
最初使用的默认值。
当然,如果选项的实际值匹配该备选项, 则会显示实际值,而非 default。
:format format-string ¶该字符串会被插入到缓冲区中,用来表示对应类型的值。 在 format-string 中可以使用以下 ‘%’ 转义符:
显示标记为按钮的文本 button。
:action 属性指定用户点击该按钮时执行的操作;
其值是一个接受两个参数的函数——按钮所在的界面组件,以及事件。
无法指定两个拥有不同操作的独立按钮。
使用 :sample-face 指定的特殊 face 显示 sample。
替换为该项的值。值的显示方式取决于项的类型, (对于变量而言)还取决于其自定义类型。
替换为该项的文档字符串。
与 ‘%d’ 类似,但如果文档字符串超过一行, 会添加一个按钮,用于控制显示全部内容还是只显示第一行。
在此处替换为标签。标签通过 :tag 关键字指定。
显示一个字面量 ‘%’。
:action action ¶用户点击按钮时执行 action。
:button-face face ¶将 face(一个 face 名或 face 名列表) 用于 ‘%[…%]’ 显示的按钮文本。
:button-prefix prefix ¶:button-suffix suffix用于指定按钮之前和之后显示的文本。 每一项可以是:
nil不插入任何文本。
直接插入该字符串。
使用该符号的值。
:tag tag使用字符串 tag 作为对应类型的值(或值的一部分)的标签。
为自定义界面提供清晰易懂的标签非常重要,
尤其是在使用 restricted-sexp 类型或定义新类型时。
See 定义新类型。
:doc doc ¶使用 doc 作为该类型对应值(或值的一部分)的文档字符串。
要使其生效,必须为 :format 指定值,
并在其中使用 ‘%d’ 或 ‘%h’。
通常为某个类型指定文档字符串,
是为了提供更多关于 choice 类型内部备选项
或其他复合类型各部分含义的信息。
:help-echo motion-doc ¶当你通过 widget-forward 或 widget-backward
移动到该项时,会在回显区显示字符串 motion-doc。
此外,motion-doc 还会用作鼠标的 help-echo 字符串,
它实际上可以是一个函数或表达式,求值后得到帮助字符串。
如果是函数,会以该界面组件为唯一参数调用它。
:match function ¶指定如何判断一个值是否匹配该类型。
对应的值 function 应该是一个接受两个参数的函数:
一个组件和一个值;如果值合法则返回非 nil。
:match-inline function ¶指定如何判断一个内联值是否匹配该类型。
对应的值 function 应该是一个接受两个参数的函数:
一个组件和一个内联值;如果值合法则返回非 nil。
关于内联值的更多信息,参见 列表内拼接。
:validate function为输入指定校验函数。function 接受一个组件作为参数,
如果组件当前值合法则返回 nil。
否则返回包含非法数据的组件,
并将该组件的 :error 属性设为描述错误的字符串。
:type-error string ¶string 用于描述一个值为何不匹配该类型,
由 :match 函数判断。
当 :match 函数返回 nil 时,
组件的 :error 属性会被设为 string。
在前面的章节中,我们介绍了如何为 defcustom 构造复杂的类型规范。
某些情况下,你可能希望给这样的类型规范赋予一个名称。
最典型的场景是:当你为多个用户选项使用 相同类型 时——
不必在每个选项中重复书写类型规范,你可以为类型规范命名,
然后在每个 defcustom 中直接使用该名称。
另一种场景是:用户选项的值是 递归数据结构。
为了让数据类型能够引用自身,它必须拥有名称。
由于自定义类型是通过界面组件(widget)实现的, 定义新自定义类型的方式就是定义一个新组件。 我们不会在这里详细描述组件接口,相关内容请参见 Introduction in The Emacs Widget Library。 我们将通过一个简单示例,演示定义新自定义类型所需的**最小功能集**。
(define-widget 'binary-tree-of-string 'lazy
"A binary tree made of cons-cells and strings."
:offset 4
:tag "Node"
:type '(choice (string :tag "Leaf" :value "")
(cons :tag "Interior"
:value ("" . "")
binary-tree-of-string
binary-tree-of-string)))
(defcustom foo-bar ""
"Sample variable holding a binary tree of strings."
:type 'binary-tree-of-string)
用于定义新组件的函数名为 define-widget。
第一个参数是我们要作为新组件类型的符号;
第二个参数是代表已有组件的符号,新组件将基于与该现有组件的差异来定义。
对于定义新自定义类型的用途来说,lazy 组件非常合适,
因为它接受一个 :type 关键字参数,其语法与同名的 defcustom 关键字参数一致。
第三个参数是新组件的文档字符串,
你可以通过命令 M-x widget-browse RET binary-tree-of-string RET
查看该字符串。
在这些必选参数之后是关键字参数。
其中最重要的是 :type,它描述此组件要匹配的数据类型。
在本例中,binary-tree-of-string 被定义为:
要么是一个字符串,要么是一个 cons 单元,
且其 car 和 cdr 本身又都是 binary-tree-of-string。
注意这里对**正在定义中的组件类型**的引用。
:tag 是另一个重要的关键字参数,因为我们的新组件使用了 lazy 组件。
默认情况下,lazy 组件没有标签,
如果缺少标签,自定义缓冲区会显示整个组件的值(即正在自定义的用户选项的值)。
这通常不是合适的做法,因此我们为 binary-tree-of-string 组件提供了一个名称字符串。
:offset 参数用于确保子节点相对于父节点缩进 4 个空格,
让树结构在自定义缓冲区中清晰可见。
后面的 defcustom 展示了如何将新组件当作普通自定义类型使用。
lazy 这个名字的由来是:
其他复合组件在缓冲区中实例化时,会将其下层组件转换为内部形式。
这种转换是递归的,下层组件会继续转换 它们 的下层组件。
如果数据结构本身是递归的,这种转换就会造成**无限递归**。
lazy 组件可以避免这种递归:它只在需要时才转换其 :type 参数。
下面的函数分别负责应用用户对变量和 face 的自定义设置。
当用户在自定义界面中执行 ‘Save for future sessions’(保存为后续会话使用)时,
系统会将一个 custom-set-variables 和/或 custom-set-faces 表达式
写入自定义文件,以便在 Emacs 下次启动时求值。
该函数应用由 args 指定的变量自定义设置。 args 中的每个参数格式应为:
(var expression [now [request [comment]]])
var 是变量名(一个符号),expression 是求值后得到目标自定义值的表达式。
如果变量 var 对应的 defcustom 形式
在本次 custom-set-variables 调用之前已经被求值,
那么 expression 会被立即求值,并将变量的值设为结果。
否则,expression 会被存入变量的 saved-value 属性中,
等到相关 defcustom 被调用时再求值(通常是在定义该变量的库被加载到 Emacs 时)。
now、request 和 comment 仅供内部使用,可以省略。
now 若非 nil,表示**立即**设置变量的值,
即使该变量的 defcustom 形式尚未被求值。
request 是需要立即加载的特性列表(see 功能)。
comment 是描述该自定义项的字符串。
该函数应用由 args 指定的 face 自定义设置。 args 中的每个参数格式应为:
(face spec [now [comment]])
face 是 face 名(一个符号),spec 是该 face 的自定义规格(see Defining Faces)。
now 和 comment 仅供内部使用,可以省略。
now 若非 nil,表示**立即**应用该 face 规格,
即使 defface 形式尚未被求值。
comment 是描述该自定义项的字符串。
自定义主题(Custom themes)是可以**整体启用或禁用**的一组设置集合。 See Custom Themes in The GNU Emacs Manual。 每个自定义主题都由一个 Emacs Lisp 源文件定义,该文件应遵循本节描述的规范。 (你不必手动编写自定义主题,也可以使用类似自定义界面的工具创建; See Creating Custom Themes in The GNU Emacs Manual。)
自定义主题文件应命名为 foo-theme.el,
其中 foo 是主题名称。
文件中的第一个 Lisp 表达式应为调用 deftheme,
最后一个表达式应为调用 provide-theme。
该宏将 theme(一个符号)声明为自定义主题的名称。
可选参数 doc 应为描述该主题的字符串;
当用户调用 describe-theme 命令,
或在 ‘*Custom Themes*’ 缓冲区中按下 ? 时,会显示这段描述。
剩余参数 properties 用于传递包含主题属性的属性列表。
支持以下属性:
:family一个符号,用于标识主题所属的 “family(系列)”。 主题的 系列(family) 是一组在细节上有所不同的相似主题, 例如分别适用于框架浅色、深色背景的 face 颜色。
:kind一个符号。如果某个主题已启用,且该属性值为 color-scheme,
则 theme-choose-variant 命令会查找同一系列下的其他可用主题,
以便进行主题切换。其他值目前未定义,不应使用。
:background-mode一个符号,为 light(浅色)或 dark(深色)。
该属性目前暂未使用,但仍建议写明。
有两个特殊主题名称禁止使用(使用会报错):
user 是存储用户直接自定义设置的虚拟主题,
changed 是存储在自定义系统之外所做修改的虚拟主题。
该宏声明名为 theme 的主题已完整定义。
在 deftheme 和 provide-theme 之间是用于指定主题设置的 Lisp 表达式:
通常是调用 custom-theme-set-variables 和/或
调用 custom-theme-set-faces。
该函数指定自定义主题 theme 的变量设置。 theme 应为符号。args 中的每个参数格式为:
(var expression [now [request [comment]]])
列表中各项含义与 custom-set-variables 一致。See 应用自定义设置。
该函数指定自定义主题 theme 的 face 设置。 theme 应为符号。args 中的每个参数格式为:
(face spec [now [comment]])
列表中各项含义与 custom-set-faces 一致。See 应用自定义设置。
理论上,主题文件也可以包含其他 Lisp 表达式,这些表达式会在加载主题时执行, 但这属于不良写法。 为防止加载包含恶意代码的主题,Emacs 在首次加载任何非内置主题前, 都会显示源文件并请求用户确认。 因此,主题通常不会被字节编译, 且 Emacs 在加载主题时,通常优先读取源文件。
以下函数可用于以编程方式启用和禁用主题:
如果 theme(符号)是一个已加载到 Emacs 中的自定义主题名称
(无论是否启用),该函数返回非 nil;否则返回 nil。
该变量的值是已加载到 Emacs 中的主题列表。
每个主题由一个 Lisp 符号(主题名)表示。
该变量的默认值包含两个虚拟主题:(user changed)。
changed 主题存储应用任何自定义主题之前的设置
(例如在自定义系统外设置的变量)。
user 主题存储用户自定义并保存的设置。
通过 deftheme 宏声明的其他主题会被添加到该列表头部。
该函数从源文件中加载名为 theme 的自定义主题,
在变量 custom-theme-load-path 指定的目录中查找源文件。
See Custom Themes in The GNU Emacs Manual。
它还会启用该主题(除非可选参数 no-enable 非 nil),
使其变量与 face 设置生效。
除非可选参数 no-confirm 非 nil,
否则加载主题前会提示用户确认。
该函数在 custom-theme-load-path 中搜索并加载提供 feature 的文件。
它类似于函数 require(see 功能),
区别在于它搜索 custom-theme-load-path 而非 load-path
(see 库搜索)。
在某些自定义主题需要加载辅助 Lisp 文件,而 require 不适用时,该函数很有用。
如果根据 featurep 判断,符号 feature 尚未存在于当前 Emacs 会话中,
则 require-theme 会在 custom-theme-load-path 指定的目录中,
依次查找后缀为 ‘.elc’ 或 ‘.el’ 的 feature 文件。
若成功找到并加载了提供 feature 的文件,
require-theme 返回 feature。
可选参数 noerror 决定搜索或加载失败时的行为:
若为 nil,函数会报错;否则返回 nil。
如果文件加载成功但未提供 feature,
require-theme 仍然会报错,且无法抑制。
启用名为 theme 的自定义主题。 如果该主题未加载,则报错。
禁用名为 theme 的自定义主题。
主题仍保持加载状态,后续调用 enable-theme 可重新启用。
加载 Lisp 代码文件,就是将其内容以 Lisp 对象的形式载入 Lisp 环境。 Emacs 会查找并打开该文件,读取文本,对每个表达式求值,然后关闭文件。 这样的文件也被称为 Lisp library。
加载函数会对文件中的所有表达式求值,这与 eval-buffer
函数对缓冲区中所有表达式求值的方式类似。
区别在于:加载函数读取并求值的是磁盘上的文件文本,
而非 Emacs 缓冲区中的文本。
被加载的文件必须包含 Lisp 表达式,可以是源代码,也可以是字节编译后的代码。 文件中的每个表达式都称为 顶层表达式(top-level form)。 可加载文件中的表达式没有特殊格式; 文件中的任意表达式都可以直接输入到缓冲区中并在那里求值。 (事实上,绝大多数代码都是这样测试的。) 这些表达式通常是函数定义和变量定义。
Emacs 还可以加载编译后的动态模块:这类共享库可为 Emacs Lisp 程序 提供额外功能,就像用 Emacs Lisp 编写的软件包一样。 加载动态模块时,Emacs 会调用一个特定名称的初始化函数, 该函数必须由模块实现,并将新增的函数和变量暴露给 Emacs Lisp 程序。
如需了解某些 Emacs 原语预先需要的外部库的按需加载方式,see Dynamically Loaded Libraries。
Emacs Lisp 提供了多种加载接口。例如,
autoload 会为文件中定义的函数创建一个占位对象;
调用这个自动加载函数时,会加载对应文件以获取函数的实际定义(see 自动加载)。
require 会在文件尚未加载时加载它(see 功能)。
最终,这些功能都会调用 load 函数来完成实际加载工作。
该函数查找并打开指定的 Lisp 代码文件,对其中所有表达式求值,然后关闭文件。
查找文件时,load 首先寻找名为
filename.elc 的文件(即文件名是 filename 附加扩展名 ‘.elc’)。
若该文件存在,且 Emacs 编译时启用了原生编译支持(see Lisp 本地代码编译),
load 会尝试查找对应的 ‘.eln’ 文件;
若找到,则加载该文件而非 filename.elc。
否则,加载 filename.elc(并在后台启动原生编译以生成缺失的 ‘.eln’ 文件,
编译完成后再加载该文件)。
若不存在 filename.elc,load 会查找名为 filename.el 的文件,
若存在则加载。
若 Emacs 编译时支持动态模块(see Emacs 动态模块),
load 接下来会查找名为 filename.ext 的文件,
其中 ext 是系统相关的共享库扩展名(GNU 和 Unix 系统上为 ‘.so’)。
最后,若以上文件名均未找到,load 会查找无任何后缀的 filename 文件,
若存在则加载。
(load 函数对 filename 的处理逻辑较为简单:
极端情况下,若存在名为 foo.el.el 的文件,执行 (load "foo.el") 确实会找到它。)
如果自动压缩模式(默认启用)处于开启状态,
当 load 找不到文件时,会先搜索该文件的压缩版本,再尝试其他文件名。
若找到压缩版本,则解压缩并加载。
它会通过将 jka-compr-load-suffixes 中的每个后缀附加到文件名后,
来查找压缩版本。
该变量的值必须是字符串列表,其标准值为 (".gz")。
若可选参数 nosuffix 非 nil,
则 load 不会尝试 ‘.elc’ 和 ‘.el’ 后缀。
此时你必须指定精确的文件名,但如果自动压缩模式开启,
load 仍会使用 jka-compr-load-suffixes 查找压缩版本。
通过指定精确文件名并将 nosuffix 设为 t,
可避免尝试 foo.el.el 这类文件名。
若可选参数 must-suffix 非 nil,
则 load 要求所用文件名必须以 ‘.el’、‘.elc’(可附加压缩后缀)
或共享库扩展名结尾,除非文件名中包含显式的目录名。
若选项 load-prefer-newer 非 nil,
则在搜索后缀时,load 会选择修改时间最新的文件版本(‘.elc’、‘.el’ 等)。
这种情况下,即使存在 ‘.eln’ 原生编译文件,load 也不会加载它。
若 filename 是相对文件名(如 foo 或 baz/foo.bar),
load 会通过变量 load-path 搜索文件。
它将 filename 附加到 load-path 列出的每个目录后,
加载第一个找到的匹配文件。
仅当当前默认目录在 load-path 中指定时(nil 代表默认目录),
才会尝试该目录。
load 会先在 load-path 的第一个目录中尝试所有三种可能的后缀,
再在第二个目录中尝试所有三种后缀,依此类推。See 库搜索。
无论最终找到的文件名和所在目录是什么,
Emacs 都会将变量 load-file-name 的值设为该文件的完整名称。
若收到警告提示 foo.elc 比 foo.el 旧, 说明你应考虑重新编译 foo.el。See 字节编译。
加载源文件(未编译)时,load 会执行字符集转换,
与 Emacs 访问该文件时的行为一致。See Coding Systems。
加载未编译文件时,Emacs 会尝试展开文件中包含的所有宏(see 宏)。 我们将此称为 立即宏展开(eager macro expansion)。 这种做法(而非延迟到相关代码运行时再展开) 能显著提升未编译代码的执行速度。 有时,由于循环依赖,宏展开无法完成。 最简单的例子是:你正在加载的文件引用了另一个文件中定义的宏, 而该文件又依赖于你正在加载的文件。 此时 Emacs 会抛出错误(提示 ‘因循环依赖跳过立即宏展开…’), 并给出问题详情。 你需要重构代码以避免这种情况。 加载编译文件不会触发宏展开,因为这一过程应已在编译时完成。See 宏与字节编译。
加载过程中,除非 nomessage 非 nil,
否则回显区会显示 ‘Loading foo...’ 和 ‘Loading foo...done’ 这类提示。
若加载的是原生编译的 ‘.eln’ 文件,提示信息会明确说明。
加载文件时出现的未处理错误会终止加载过程。
如果此次加载是因 autoload 触发,
加载过程中创建的所有函数定义都会被撤销。
若 load 找不到要加载的文件,通常会抛出 file-error 错误
(提示 ‘无法打开加载文件 filename’)。
但如果 missing-ok 非 nil,则 load 仅返回 nil。
你可以通过变量 load-read-function 指定一个函数,
让 load 用该函数替代 read 来读取表达式。
详见下文。
若文件加载成功,load 返回 t。
该命令加载文件 filename。
若 filename 是相对文件名,则使用当前默认目录。
该命令不使用 load-path,也不会附加后缀,
但会查找压缩版本(若自动压缩模式启用)。
如果你需要精确指定要加载的文件名,可使用此命令。
该命令加载名为 library 的库。
除了交互式读取参数的方式不同外,其功能与 load 等效。
See Lisp Libraries in The GNU Emacs Manual。
当 Emacs 正在加载文件时,该变量值为非 nil;否则为 nil。
当 Emacs 正在加载文件时,该变量的值是本节前文所述搜索过程中找到的文件名。
该变量为 load 和 eval-region 指定替代 read 的表达式读取函数。
该函数应像 read 一样接受一个参数。
默认情况下,该变量的值为 read。See 输入函数。
相比使用该变量,更规范的方式是使用一个更新的特性:
将该函数作为 read-function 参数传递给 eval-region。
See Eval。
关于 load 在 Emacs 构建过程中的使用方式,详见
Building Emacs。
本节说明 load 函数尝试的具体后缀相关技术细节。
该变量是一个后缀列表,用于标识 Emacs Lisp 文件(编译版或源码版)。
列表中不应包含空字符串。当 load 为指定文件名附加 Lisp 后缀时,
会按顺序使用这些后缀。其标准值为 (".elc" ".el"),
对应上一节所述的行为逻辑。
该变量是一个后缀列表,用于标识同一文件的不同存储形式。
此列表通常应以空字符串开头。当 load 搜索文件时,
会先按顺序将该列表中的后缀附加到文件名后进行查找,
再尝试其他文件名。
启用自动压缩模式时,会将 jka-compr-load-suffixes 中的后缀添加到该列表;
禁用自动压缩模式时,则会移除这些后缀。
若禁用自动压缩模式,load-file-rep-suffixes 的标准值为 ("");
鉴于 jka-compr-load-suffixes 的标准值是 (".gz"),
启用自动压缩模式时,load-file-rep-suffixes 的标准值为 ("" ".gz")。
当 load 函数的 must-suffix 参数非 nil 时,
该函数返回 load 应按顺序尝试的所有后缀列表。
此函数会同时考虑 load-suffixes 和 load-file-rep-suffixes 的值。
若 load-suffixes、jka-compr-load-suffixes 和 load-file-rep-suffixes
均为标准值:启用自动压缩模式时,返回 (".elc" ".elc.gz" ".el" ".el.gz");
禁用自动压缩模式时,返回 (".elc" ".el")。
综上,load 通常先尝试 (get-load-suffixes) 返回值中的后缀,
再尝试 load-file-rep-suffixes 中的后缀。
若 nosuffix 非 nil,则跳过前一组后缀;
若 must-suffix 非 nil,则跳过后一组后缀。
若该选项非 nil,load 不会在找到第一个存在的后缀时停止,
而是测试所有后缀,并使用修改时间最新的文件。
Emacs 加载 Lisp 库时,会在变量 load-path 指定的目录列表中搜索该库。
该变量的值是一个目录列表,使用 load 加载文件时会搜索这些目录。
列表中的每个元素要么是字符串(必须为目录路径),要么是 nil(代表当前工作目录)。
Emacs 启动时,会通过多个步骤初始化 load-path 的值:
首先,它会根据编译时设置的默认路径,查找自身 Lisp 文件所在的目录,
并将该目录保存到 lisp-directory 中。
通常,该目录是安装 *.elc 文件的路径,格式类似:
"/usr/local/share/emacs/version/lisp"
其中 version 为 Emacs 的版本号。 (在本节及后续示例中,请将 /usr/local 替换为你系统中 Emacs 的实际安装前缀。) 该目录及其子目录包含 Emacs 自带的标准 Lisp 文件; 若 Emacs 无法找到自身的 Lisp 文件,将无法正常启动。
若你从编译目录运行 Emacs(即未安装的可执行文件),
则 Emacs 会改用编译源码所在目录的 lisp 子目录来初始化 lisp-directory。
随后,Emacs 会以该 lisp-directory 初始化 load-path。
若你在源码目录外的独立目录编译 Emacs,
它还会将编译目录的 lisp 子目录添加到 load-path。
上述所有目录均以绝对文件名形式存储在上述两个变量中。
除非你使用 --no-site-lisp 选项启动 Emacs,
否则它会在 load-path 的前端额外添加两个 site-lisp 目录。
这些目录用于存放本地安装的 Lisp 文件,格式通常为:
"/usr/local/share/emacs/version/site-lisp"
和
"/usr/local/share/emacs/site-lisp"
第一个目录用于当前 Emacs version 版本的本地安装文件; 第二个目录用于所有已安装 Emacs 版本共享的本地文件。 (若 Emacs 以未安装状态运行,还会添加源码目录和编译目录下的 site-lisp 子目录(若存在); 但通常源码目录和编译目录不含 site-lisp 子目录。)
若设置了环境变量 EMACSLOADPATH,它会修改上述初始化流程,
Emacs 会基于该环境变量的值初始化 load-path。
EMACSLOADPATH 的语法与 PATH 相同:
目录之间用 ‘:’ 分隔(部分操作系统为 ‘;’)。
以下是设置 EMACSLOADPATH 变量的示例(基于 sh 风格的 shell):
export EMACSLOADPATH=/home/foo/.emacs.d/lisp:
该环境变量值中的空元素(无论是末尾空元素(如上述示例中末尾的 ‘:’)、
开头空元素还是中间嵌入的空元素),都会被标准初始化流程生成的 load-path 默认值替换。
若不存在此类空元素,则 EMACSLOADPATH 会完全指定 load-path 的内容。
你必须要么包含空元素,要么显式指定标准 Lisp 文件所在目录的路径,
否则 Emacs 将无法正常运行。
(修改 load-path 的另一种方式是启动 Emacs 时使用 -L 命令行选项,详见下文。)
对于 load-path 中的每个目录,Emacs 会检查是否存在 subdirs.el 文件,
若存在则加载该文件。subdirs.el 文件在 Emacs 编译/安装时生成,
其中包含的代码会让 Emacs 将这些目录的所有子目录添加到 load-path 中——
包括直接子目录和多级嵌套子目录。
但会排除以下子目录:名称非以字母/数字开头的、名为 RCS 或 CVS 的、
以及包含 .nosearch 文件的子目录。
接下来,Emacs 会添加你通过 -L 命令行选项指定的额外加载目录 (see Action Arguments in The GNU Emacs Manual); 若存在已安装的可选软件包,还会添加这些软件包的安装目录(see Packaging Basics)。
常见做法是在初始化文件中添加代码(see The Init File),
将一个或多个目录添加到 load-path。例如:
(push "~/.emacs.d/lisp" load-path)
See push,查看 push 的说明。
转储 Emacs 时会使用 load-path 的一个特殊值。
如果你使用 site-load.el 或 site-init.el 文件来定制转储后的 Emacs(see Building Emacs),
这些文件对 load-path 所做的任何修改在转储后都会丢失。
该变量保存一个字符串,指明存放 Emacs 自身 *.el 和 *.elc 文件的目录。 通常这是 Emacs 安装目录结构中这些文件所在的位置; 如果是从编译目录直接运行 Emacs,则指向编译所用源码目录中的 lisp 子目录。
该命令查找库 library 对应的精确文件名。
它搜索库的方式与 load 相同,参数 nosuffix 的含义也与 load 中一致:
不向指定的 library 名称添加 ‘.elc’ 或 ‘.el’ 后缀。
若 path 非 nil,则使用该目录列表而非 load-path。
当 locate-library 被程序调用时,以字符串形式返回文件名。
当用户交互式运行 locate-library 时,参数 interactive-call 为 t,
指示 locate-library 在回显区显示文件名。
该命令显示被 遮蔽(shadowed) 的 Emacs Lisp 文件列表。
被遮蔽的文件是指:虽然位于 load-path 的某个目录中,
但由于 load-path 中靠前的目录里存在同名文件,
导致其通常不会被加载的文件。
例如,假设 load-path 设置为:
("/opt/emacs/site-lisp" "/usr/share/emacs/29.1/lisp")
且两个目录中都有名为 foo.el 的文件。
那么 (require 'foo) 永远不会加载第二个目录中的文件。
这种情况可能表明 Emacs 的安装存在问题。
当从 Lisp 中调用此函数时,会打印被遮蔽文件的信息,而非在缓冲区中显示。
若可选参数 stringp 非 nil,则以字符串形式返回这些被遮蔽文件。
如果 Emacs 编译时启用了原生编译支持(see Lisp 本地代码编译),
当通过 load-path 搜索到 ‘.elc’ 字节编译文件时,
Emacs 会尝试查找对应的存放原生编译代码的 ‘.eln’ 文件。
原生编译文件的搜索目录由 native-comp-eln-load-path 指定。
该变量保存一个目录列表,Emacs 会在其中搜索原生编译的 ‘.eln’ 文件。
列表中非绝对路径的文件名会被解释为相对于 invocation-directory 的路径(see Operating System Environment)。
列表中的最后一个目录为系统目录,即 Emacs 编译安装过程中安装 ‘.eln’ 文件的目录。
在列表中的每个目录下,Emacs 会在一个子目录中查找 ‘.eln’ 文件,
该子目录名由 Emacs 版本和一个依赖当前原生编译 ABI 的 8 位哈希值构成;
此子目录名保存在变量 comp-native-version-dir 中。
当 Emacs Lisp 程序中包含带有非 ASCII 字符的字符串常量时, 这些字符在 Emacs 内部可以表示为单字节字符串或多字节字符串(see Text Representations)。 具体使用哪种表示方式,取决于文件被读入 Emacs 的方式。 如果读取时经过解码并转为多字节表示,Lisp 程序的文本就是多字节文本, 其字符串常量也将是多字节字符串。 如果包含 Latin-1 字符(举例)的文件在读取时**未经过解码**, 程序文本将是单字节文本,其字符串常量也将是单字节字符串。 See Coding Systems。
在大多数 Emacs Lisp 程序中,非ASCII 字符串是多字节字符串这一点通常不会被察觉,
因为将它们插入到单字节缓冲区时会自动转换为单字节。
但是,如果这确实会带来影响,你可以通过在局部变量区中写入
‘coding: raw-text’,强制某个 Lisp 文件被按单字节解析。
使用该标记后,文件将无条件地被当作单字节处理。
在为写成 ?vliteral 形式的非 ASCII 字符设置按键绑定时,这一点可能很重要。
自动加载(autoload) 机制允许你先登记一个函数或宏的存在, 但推迟加载定义它的文件。 第一次调用该函数时,会自动加载对应的库,以安装真正的定义及其他相关代码, 然后运行真正的定义,就像它早已被加载一样。 自动加载也可以通过查看函数或宏的文档(see 文档基础) 以及变量和函数名的补全触发(见下文 see 按前缀自动加载)。
配置自动加载函数有两种方式:一是调用
autoload 函数,二是在源码中真正的定义之前编写一条「魔法注释」。
autoload 是实现自动加载的底层原语,任何 Lisp 程序都可在任意时机调用它。
对于随 Emacs 一同安装的软件包而言,魔法注释是让函数支持自动加载最便捷的方式。
这些注释本身不执行任何操作,但会作为 loaddefs-generate 命令的指引——
该命令会构造对 autoload 的调用,并安排在 Emacs 构建时执行这些调用。
该函数定义名为 function 的函数(或宏),使其从 filename 自动加载。 字符串 filename 指定要加载的文件,以获取 function 的实际定义。
若 filename 既不包含目录名,也无 .el 或 .elc 后缀,
此函数会强制添加其中一个后缀,且不会加载仅为 filename 无附加后缀的文件。
(变量 load-suffixes 规定了具体要求的后缀。)
参数 docstring 是该函数的文档字符串。
在调用 autoload 时指定文档字符串,可在不加载函数实际定义的情况下查看文档。
通常,此处的文档字符串应与函数定义本身的文档字符串完全一致;
若不一致,函数定义中的文档字符串会在加载时生效。
若 interactive 非 nil,表示 function 可被交互式调用。
这使得 M-x 中的补全功能无需加载 function 的实际定义即可工作。
此处无需给出完整的交互式规范——除非用户实际调用 function,
而此时正是加载实际定义的时机。
若 interactive 是一个列表,则会被解析为该命令适用的模式列表。
除普通函数外,你也可以为宏和按键映射表设置自动加载:
若 function 实际是宏,需将 type 指定为 macro;
若 function 实际是按键映射表,需将 type 指定为 keymap。
Emacs 的多个功能模块需要在不加载实际定义的情况下知晓这些信息。
当前缀键的绑定为符号 function 时,
自动加载的按键映射表会在按键查找过程中自动加载。
而以其他方式访问该按键映射表时,不会触发自动加载——
尤其是当 Lisp 程序从某个变量的值中获取该映射表并调用 keymap-set 时,
即便变量名与符号 function 相同,也不会触发自动加载。
若 function 已有非空的函数定义(且该定义并非自动加载对象),
此函数不执行任何操作并返回 nil。
否则,它会构造一个自动加载对象(see 自动加载类型),
并将其存储为 function 的函数定义。
自动加载对象的格式如下:
(autoload filename docstring interactive type)
For example,
(symbol-function 'run-prolog)
⇒ (autoload "prolog" 169681 t nil)
在这个例子中,"prolog" 是待加载文件的名称,
169681 指向 emacs/etc/DOC 文件中的文档字符串(see 文档基础),
t 表示该函数可交互式调用,nil 表示它既非宏也非按键映射表。
如果 object 是一个自动加载对象(autoload object),该函数返回非 nil 值。例如,要检查 run-prolog 是否被定义为自动加载函数,可执行以下代码:
(autoloadp (symbol-function 'run-prolog))
自动加载文件通常包含其他定义,且可能会引入(require)或提供(provide)一个或多个功能特性(feature)。如果文件未完全加载(因执行其内容时出错),加载过程中产生的所有函数定义或 provide 调用都会被撤销。这样做是为了确保下次调用任何从该文件自动加载的函数时,会重新尝试加载该文件。若不执行此操作,文件中的部分函数可能会因加载中断而被定义,但由于文件后续未成功加载的某些子例程缺失,这些函数将无法正常工作。
如果自动加载文件未能定义所需的 Lisp 函数或宏,则会触发错误,错误数据为 "Autoloading failed to define function function-name"。
自动加载魔术注释(通常称为 自动加载标记(autoload cookie))由 ‘;;;###autoload’ 组成,需单独写在一行,且紧跟在其可自动加载的源文件中函数的实际定义之前。函数 loaddefs-generate 会将对应的 autoload 调用写入 loaddefs.el 文件。
(用作自动加载标记的字符串以及 loaddefs-generate 生成的文件名可修改,默认值如上,详见下文。)
构建 Emacs 时会加载 loaddefs.el,从而调用 autoload 函数。
相同的魔术注释可将任意类型的表单(form)复制到 loaddefs.el 中。紧跟魔术注释的表单会被原样复制,但 例外情况 是:若该表单属于自动加载机制会特殊处理的类型(例如转换为 autoload 调用),则不会原样复制。不会原样复制的表单类型如下:
defun 和 defmacro;还包括 cl-defun 和
cl-defmacro(see Argument Lists in Common Lisp Extensions),
以及 define-overloadable-function(参见 mode-local.el 中的注释)。
define-minor-mode、define-globalized-minor-mode、
define-generic-mode、define-derived-mode、
define-compilation-mode 和 define-global-minor-mode。
defcustom、defgroup、deftheme、defclass
(see EIEIO in EIEIO),以及 define-skeleton
(see Autotyping in Autotyping)。
你也可以使用魔术注释,让某个表单仅在构建阶段执行,而 不 在加载文件本身时执行。要实现此效果,需将该表单与魔术注释写在 同一行。由于该表单位于注释中,加载源文件时不会执行任何操作;但 loaddefs-generate 会将其复制到 loaddefs.el 中,在构建 Emacs 时执行该表单。
以下示例展示如何通过魔术注释为 doctor 函数配置自动加载:
;;;###autoload (defun doctor () "Switch to *doctor* buffer and start giving psychotherapy." (interactive) (switch-to-buffer "*doctor*") (doctor-mode))
这是在 loaddefs.el 中生成的内容:
(autoload 'doctor "doctor" "\ Switch to *doctor* buffer and start giving psychotherapy. \(fn)" t nil)
虽然 loaddefs.el 并非用于编辑,但我们仍尽量使其对用户具有一定可读性。例如,对 defvar 值中的控制字符进行转义,并在文档字符串的双引号后面立即插入反斜杠与换行符,以控制行长度。
各种帮助函数(see 帮助函数)在显示时,会将文档字符串用法部分中的 ‘(fn)’ 替换为函数名。
如果你使用非常规宏(不属于已知并被识别的函数定义方式)来编写函数定义,普通的自动加载魔术注释会将整个定义复制到 loaddefs.el。这并不可取。你可以改用下面的写法,将所需的 autoload 调用写入 loaddefs.el:
;;;###autoload (autoload 'foo "myfile") (mydefunmacro foo ...)
你可以使用非默认字符串作为自动加载标记,并将对应的自动加载调用写入文件名不同于默认 loaddefs.el 的文件中。 Emacs 提供了两个变量来控制这一点:
该常量的值是一个匹配自动加载标记的正则表达式。
loaddefs-generate 会将标记后面的 Lisp 表单复制到它生成的自动加载文件中。
它可以匹配类似 ‘;;;###autoload’ 和 ‘;;;###calc-autoload’ 这样的注释。
该变量的值指定存放自动加载调用的 Emacs Lisp 文件名。 默认值为 loaddefs.el,但你可以覆盖它,例如在 .el 文件的局部变量区段中设置(see 文件局部变量)。 自动加载文件被假定包含以换页符开头的尾部内容。
下面的函数可用于显式加载自动加载对象所指定的库:
该函数执行由 autoload 指定的加载操作,autoload 必须是自动加载对象。
可选参数 name 若非 nil,则应为一个符号,其函数值为 autoload;
此时该函数的返回值是该符号新的函数值。
如果可选参数 macro-only 的值为 macro,则该函数只加载宏,不加载普通函数。
在对 describe-variable 和 describe-function 命令进行补全时,Emacs 会尝试加载可能包含与补全前缀匹配的定义的文件。变量 definition-prefixes 保存一个哈希表,它将前缀映射到需要为此加载的对应文件列表。该映射的条目由 register-definition-prefixes 调用添加,而这些调用由 loaddefs-generate 生成(see 自动加载)。
不包含任何值得加载的定义的文件(例如测试文件),应当将 autoload-compute-prefixes 作为文件局部变量设为 nil。
除非确实必要,否则不要添加自动加载注释。自动加载的代码会始终全局可见。一旦某个对象被自动加载,在用户已经习惯无需显式加载(即可使用之后,就无法以兼容方式退回到非自动加载状态)。
python-mode 函数的定义,这样用户只需通过 M-x python-mode 即可加载该库。
find-exec-terminator 这类变量。)
(defvar foo) 消除未定义变量的警告,使用 declare-function(see 告知编译器某个函数已被定义)消除未定义函数的警告;或者使用 require 引入相关库;亦或使用显式的自动加载 语句。
你可以在一个 Emacs 会话中多次加载同一个文件。例如,当你在缓冲区中编辑并重写并重新安装了某个函数定义后,若想恢复到原始版本,可以通过重新加载该函数所在的源文件来实现。
加载或重新加载文件时,请记住:load 和 load-library 函数会自动加载字节编译后的文件,而非同名的未编译文件。如果你重写了某个文件并打算保存与重新安装,就需要对新版本进行字节编译;否则 Emacs 会加载旧的字节编译文件,而不是你新修改的未编译文件!
如果发生这种情况,加载时显示的信息会包含 ‘(compiled; note, source is newer)’,以提醒你重新编译。
在 Lisp 库文件中编写表单时,要考虑到该文件可能会被多次加载。例如,思考每个变量在库被重新加载时是否应当被重新初始化;如果变量已经初始化,defvar 不会改变其值。(See 定义全局变量。)
向关联列表(alist)添加元素的最简单写法如下:
(push '(leif-mode " Leif") minor-mode-alist)
但如果库被重新加载,这会导致添加多个重复元素。要避免该问题,请使用 add-to-list(see 修改列表变量):
(add-to-list 'minor-mode-alist '(leif-mode " Leif"))
有时你需要显式判断某个库是否已经加载。如果该库使用 provide 提供了命名功能(feature),你可以在文件中更早的位置使用 featurep 来判断 provide 调用是否已经执行过(see 功能)。
或者,你也可以使用类似下面的代码:
(defvar foo-was-loaded nil) (unless foo-was-loaded execute-first-time-only (setq foo-was-loaded t))
provide 和 require 是 autoload 之外的另一种自动加载文件的方式。它们基于命名的 功能(feature) 工作。自动加载由调用特定函数触发,而功能则是在其他程序首次按名称请求时被加载。
功能名是一个符号,代表一组函数、变量等的集合。定义它们的文件应当 提供(provide) 该功能。使用这些功能的其他程序可以通过 需求(require) 该功能来确保其已被定义。如果文件尚未加载,这会加载对应的定义文件。
要需求某个功能存在,以功能名作为参数调用 require。
require 会检查全局变量 features,判断所需功能是否已经提供。
如果没有,它会从对应的文件加载该功能。
该文件应当在顶层调用 provide,将该功能加入 features;
如果没有这样做,require 会发出错误信号。
例如,在 idlwave.el 中,idlwave-complete-filename 的定义包含如下代码:
(defun idlwave-complete-filename ()
"Use the comint stuff to complete a file name."
(require 'comint)
(let* ((comint-file-name-chars "~/A-Za-z0-9+@:_.$#%={}\\-")
(comint-completion-addsuffix nil)
...)
(comint-dynamic-complete-filename)))
表达式 (require 'comint) 会在尚未加载时加载 comint.el 文件,确保 comint-dynamic-complete-filename 已被定义。
功能通常以提供它的文件命名,因此 require 不需要指定文件名。
(注意,require 语句必须放在 let 体之外,这一点很重要。
在变量被 let 绑定期间加载库可能产生意外后果,即变量在 let 退出后会变为未绑定。)
comint.el 文件包含如下顶层表达式:
(provide 'comint)
这会将 comint 加入全局的 features 列表,此后 (require 'comint) 就知道无需执行任何操作。
当 require 在文件顶层使用时,它不仅在加载时生效,在对该文件进行字节编译时也会生效(see 字节编译)。
这是为了应对被需求的包中包含字节编译器必须知晓的宏的情况。
这也可以避免字节编译器对由 require 加载的文件中定义的函数和变量发出警告。
虽然顶层的 require 调用会在字节编译期间执行,但 provide 调用不会。
因此,你可以通过先写 provide、再对同一功能写 require,确保定义文件在字节编译前已被加载,如下例所示。
(provide 'my-feature) ; Ignored by byte compiler,
; evaluated by load.
(require 'my-feature) ; Evaluated by byte compiler.
编译器忽略 provide,然后通过加载对应文件来处理 require。
加载文件时会执行 provide 调用,因此后续的 require 在文件加载时不执行任何操作。
该函数宣告 feature 已加载或正在加载到当前 Emacs 会话中。 这意味着与 feature 相关的功能已经或将要可供其他 Lisp 程序使用。
调用 provide 的直接效果是:如果 feature 不在 features 列表中,则将其添加到列表前端,并执行所有等待该功能的 eval-after-load 代码(see 加载相关钩子)。
参数 feature 必须是一个符号。
provide 返回 feature。
如果提供了 subfeatures,它应当是一个符号列表,表示此版本 feature 提供的一组特定子功能。
你可以使用 featurep 检查某个子功能是否存在。
子功能的设计意图是:当一个包(对应一个 feature)足够复杂,需要为其不同部分或功能分别命名时使用,这些部分可能加载或未加载,可能存在或不存在于某个版本中。
see Testing Availability of Network Features 提供了一个示例。
features
⇒ (bar bish)
(provide 'foo)
⇒ foo
features
⇒ (foo bar bish)
当加载文件以满足自动加载需求,且因执行文件内容出错而中断时,加载过程中产生的所有函数定义或 provide 调用都会被撤销。See 自动加载。
该函数检查 feature 是否已存在于当前 Emacs 会话中(通过 (featurep feature) 实现;详见下文)。参数 feature 必须是一个符号。
如果该功能不存在,则 require 会通过 load 加载 filename 文件。若未提供 filename,则将符号 feature 的名称作为要加载的基础文件名。
但在此情况下,require 要求文件必须带有 ‘.el’ 或 ‘.elc’ 后缀(可附加压缩后缀);仅以 feature 为名的文件不会被使用。
(变量 load-suffixes 规定了确切的 Lisp 文件后缀要求。)
如果 noerror 为非 nil 值,则会抑制文件实际加载过程中产生的错误。此时若文件加载失败,require 返回 nil。
默认情况下,require 返回 feature。
如果文件加载成功但未提供 feature,require 会针对缺失的功能发出错误信号。
该函数的行为与 require 类似,但存在一个例外情况:当 feature 已加载时(即已存在于 features 列表中;详见下文)。
若 feature 已加载,该函数会检查提供此功能的文件是否与 filename 不同;若不同,默认会发出错误信号。
如果可选参数 noerror 的值为 reload,函数不会报错,而是强制重新加载 filename;
若 noerror 为其他非 nil 值,函数会发出警告,提示 feature 已由另一个文件提供。
如果 feature 已在当前 Emacs 会话中被提供(即 feature 是 features 的成员),该函数返回 t。
若 subfeature 为非 nil 值,则仅当该子功能也被提供时(即 subfeature 是 feature 符号的 subfeature 属性的成员),函数才返回 t。
该变量的值是一个符号列表,代表当前 Emacs 会话中已加载的功能。列表中的每个符号都是通过调用 provide 加入的。
features 列表中元素的顺序无实际意义。
use-package 宏提供了一种便捷的方式来加载功能并配置其使用方式。
它既能像 require 一样需求某个功能,又能指定功能实际加载时要运行的代码(类似加载时钩子;see 加载相关钩子)。
use-package 的声明式语法使其在用户初始化文件中使用起来格外简便。
该宏指定如何加载命名为 feature 的功能,以及如何配置和自定义其使用方式。参数 args 为若干键值对。 其中重要的关键字及其取值如下:
:init forms指定在加载 feature 之前要执行的 forms(表单)。
:config forms指定在加载 feature 之后要执行的 forms(表单)。
:defer condition若 condition 为非 nil 值,表示延迟加载 feature,直到首次使用该功能的任意自动加载命令或变量时才加载。
若 condition 为数字 n,表示在空闲 n 秒后加载 feature。
:commands commands…指定要为 feature 自动加载的命令。
:bind keybindings…指定 feature 相关命令的 keybindings(按键绑定)。每个绑定的格式为:
(key-sequence . command)
or
(:map keymap (key-sequence . command))
其中 key-sequence(按键序列)的格式需符合 kbd 宏的要求(see 按键序列)。
关于 use-package 的更多细节,参见 use-package 用户手册。
该函数返回定义 symbol(符号)的文件名。
若 type 为 nil,则接受任意类型的定义;
若 type 为 defun、defvar 或 defface,则仅分别匹配函数定义、变量定义或面孔(face)定义。
返回值通常为绝对文件名;若该定义未关联任何文件,返回值可为 nil;
若 symbol 指向一个自动加载函数,返回值可为无扩展名的相对文件名。
如果可选的第三个参数 native-p 为非 nil 值,且 Emacs 编译时启用了原生编译支持(see Lisp 本地代码编译),
该函数会尝试查找定义 symbol 的 .eln 文件,而非 .elc 或 .el 文件。
若找到对应的 .eln 文件且该文件未过期,则返回其绝对文件名;否则返回源码文件或字节编译文件的名称。
symbol-file 的实现基于变量 load-history 中的数据。
该变量的值是一个关联列表(alist),将已加载库文件的名称与它们定义的函数、变量,以及提供或需求的功能(feature)关联起来。
该关联列表中的每个元素描述一个已加载的库(包括启动时预加载的库),其结构为一个列表: CAR 部分是库的绝对文件名(字符串),其余元素的格式如下:
var符号 var 被定义为变量。
(defun . fun)函数 fun 被定义。((defun . fun) 该形式表示将 fun 定义为函数)。
(defface . face)面孔 face 被定义。
(require . feature)功能 feature 被需求(require)。
(provide . feature)功能 feature 被提供(provide)。
(cl-defmethod method specializers)通过 cl-defmethod 定义了名为 method 的方法,specializers 为其特殊化参数。
(define-type . type)类型 type 被定义。
load-history 的值中可能包含一个 CAR 为 nil 的元素,该元素描述通过 eval-buffer 在未关联文件的缓冲区中完成的定义。
命令 eval-region 会更新 load-history,但更新方式是将定义的符号添加到当前访问文件对应的元素中,而非替换该元素。See 求值。
除 load-history 外,每个函数还会在其符号属性 function-history 中记录自身的历史。
函数在此处被特殊处理的原因是:函数通常会分两步在两个不同文件中定义(其中一个通常是自动加载文件),
因此为了能够正确地 卸载(unload) 文件,需要更精确地知晓该文件对函数定义所做的修改。
符号属性 function-history 保存一个格式为 (file1 def2 file2 def3 ...) 的列表:
其中 file1 是最后修改该函数定义的文件,def2 是 file1 修改前的定义(由 file2 设置),依此类推。
逻辑上该列表应终止于首次定义该函数的文件名,但为节省空间,这最后一个元素通常会被省略。
你可以丢弃由某个库加载的函数和变量,以回收内存供其他 Lisp 对象使用。
为此,请使用函数 unload-feature:
该命令卸载提供了 feature 功能的库。
它会取消定义该库中通过 defun、defalias、subst、
defmacro、defconst、defvar 和 defcustom
定义的所有函数、宏和变量。
然后恢复这些符号原先关联的自动加载定义。
(加载时会将这些定义保存在符号的 function-history 属性中。)
在恢复之前的定义之前,unload-feature 会运行 remove-hook,
从某些钩子中移除由该库定义的函数。
这些钩子包括名称以 ‘-hook’ 结尾的变量(或已废弃的后缀 ‘-hooks’),
以及 unload-feature-special-hooks 中列出的变量,还有 auto-mode-alist。
这样做是为了防止 Emacs 因重要钩子引用了已不再定义的函数而无法正常运行。
标准卸载操作还会取消对该库中函数的 ELP 性能分析, 取消该库所提供的所有功能,并取消存放在该库定义的变量中的定时器。
如果这些措施仍不足以防止功能异常,库可以定义一个显式的卸载函数,
名为 feature-unload-function。
如果该符号被定义为函数,unload-feature 会在执行其他操作之前
无参数调用它。
该函数可以执行任何适合卸载该库的操作。
如果它返回 nil,unload-feature 会继续执行常规卸载动作;
否则认为卸载工作已完成。
通常情况下,unload-feature 拒绝卸载被其他已加载库依赖的库。
(如果库 a 中包含对 b 的 require,则 a 依赖于库 b。)
如果可选参数 force 为非 nil,则忽略依赖关系,可以卸载任意库。
unload-feature 函数由 Lisp 编写,其行为基于变量 load-history。
该变量保存一个钩子列表,在卸载库时会扫描这些钩子,以移除库中定义的函数。
你可以通过变量 after-load-functions,让 Emacs 在每次加载库时执行指定代码:
这个非常规钩子会在加载文件之后运行。钩子中的每个函数都会被传入一个参数,即刚刚加载的文件的绝对文件名。
如果你希望在加载 某个特定 库时执行代码,请使用宏 with-eval-after-load:
该宏会安排在每次加载 library 文件的末尾执行 body。如果 library 已经加载,则立即执行 body。
你不需要在文件名 library 中指定目录或扩展名。通常只需给出裸文件名,例如:
(with-eval-after-load "js" (keymap-set js-mode-map "C-c C-c" 'js-eval))
若要限制哪些文件能触发执行,可以在 library 中加入目录、扩展名或两者都加。只有其绝对真实名称(已展开所有符号链接的名称)完全匹配给定名称各部分的文件才会触发。
在下例中,位于 ..../foo/bar 目录下的 my_inst.elc 或 my_inst.elc.gz 会触发执行,但 my_inst.el 不会:
(with-eval-after-load "foo/bar/my_inst.elc" ...)
library 也可以是一个功能(即符号),此时 body 会在任何调用了 (provide library) 的文件末尾执行。
body 中出现的错误不会撤销加载操作,但会阻止 body 中后续代码的执行。
通常,设计良好的 Lisp 程序不应使用 with-eval-after-load。
如果你需要读取或设置其他库中定义的变量(那些供外部使用的变量),可以直接操作,无需等到库加载完成。
如果你需要调用该库定义的函数,你应该先加载该库,推荐使用 require(see 功能)。
Emacs 动态模块(dynamic Emacs module) 是一种共享库,可为 Emacs Lisp 程序提供额外功能,与使用 Emacs Lisp 编写的包类似。
用于加载 Emacs Lisp 包的函数同样可以加载动态模块。系统通过文件名扩展名(也称 “后缀(suffix)”)识别动态模块,该后缀与平台相关。
该变量保存模块文件的文件名扩展名,其值与系统相关。 在 POSIX 系统上为 .so,macOS 上为 .dylib,MS-Windows 上为 .dll。
在 macOS 上,动态模块除了 .dylib 之外,也可以使用后缀 .so。
每个动态模块都应导出一个名为 emacs_module_init 的 C 可调用函数,Emacs 会在通过 load 或 require 加载模块时调用它。
模块还应导出一个名为 plugin_is_GPL_compatible 的符号,表明其代码基于 GPL 或兼容协议发布;
如果程序尝试加载未导出该符号的模块,Emacs 会报错。
如果模块需要调用 Emacs 函数,应通过 Emacs 发行版中附带的头文件 emacs-module.h 所定义并说明的 API(应用程序编程接口)实现。 See Writing Dynamically-Loaded Modules 查看编写模块时使用该 API 的详细信息。
模块可以创建 user-ptr 类型的 Lisp 对象,用于存放指向模块所定义的 C 结构体的指针。
这便于保存模块创建的复杂数据结构,并将其传回给模块的函数使用。
user-ptr 对象还可以关联 终结函数(finalizer)——在对象被垃圾回收(GC)时执行的函数,
可用于释放底层数据结构占用的资源,如内存、打开的文件描述符等。See Conversion Between Lisp and Module Values。
如果参数是 user-ptr 对象,该函数返回 t。
Emacs 使用这个底层原语从指定的 file 加载模块并完成必要的初始化。
该原语会检查模块是否导出了 plugin_is_GPL_compatible 符号,调用模块的 emacs_module_init 函数,
若该函数返回错误或初始化期间用户按下 C-g,则报错。
若初始化成功,module-load 返回 t。
注意:file 必须已经带有正确的扩展名,因为与 load 不同,该函数不会自动尝试已知后缀的文件。
与 load 不同,module-load 不会将模块记入 load-history,不打印任何信息,也不防止递归加载。
因此大多数用户应使用 load、load-file、load-library 或 require,而非直接使用 module-load。
Emacs 中的可加载模块需要在 configure 时使用 --with-modules 选项启用。
Emacs Lisp 拥有一个 编译器(compiler),它可以将用 Lisp 编写的函数 转换为一种称为 字节码(byte-code) 的特殊表示形式,这种形式可以 更高效地执行。编译器会用字节码替换 Lisp 函数 定义。当调用字节码函数时,其定义 由 字节码解释器(byte-code interpreter) 求值。
由于字节编译后的代码由字节码解释器求值, 而非由机器硬件直接执行(真正的编译代码如此), 因此字节码可以在不同机器之间完全移植,无需重新编译。 但它的速度不如真正的编译代码。
一般来说,任何版本的 Emacs 都可以运行由较新版本之前
如果你永远不希望某个 Lisp 文件被编译,可以在其中
加入针对 no-byte-compile 的文件局部变量绑定,如下所示:
;; -*-no-byte-compile: t; -*-
字节编译函数的效率不如用 C 编写的原语函数, 但比用纯 Lisp 编写的版本快得多。下面是一个示例:
(defun silly-loop (n)
"Return the time, in seconds, to run N iterations of a loop."
(let ((t1 (float-time)))
(while (> (setq n (1- n)) 0))
(- (float-time) t1)))
⇒ silly-loop
(silly-loop 50000000) ⇒ 5.200886011123657
(byte-compile 'silly-loop)
⇒ [Compiled code not shown]
(silly-loop 50000000) ⇒ 0.6239290237426758
在此示例中,解释执行的代码需要 5 秒以上才能运行完毕, 而字节编译后的代码耗时不到 1 秒。 这些结果具有代表性,但实际数值可能有所不同。
你可以使用 byte-compile 函数对单个函数或宏定义进行字节编译。
使用 byte-compile-file 可以编译整个文件,
使用 byte-recompile-directory 或 batch-byte-compile
可以编译多个文件。
有时,字节编译器会产生警告和/或错误信息
(详情参见see 编译器错误)。这些信息通常
记录在名为 *Compile-Log* 的缓冲区中,
该缓冲区使用编译模式。
See Compilation Mode in The GNU Emacs Manual。
但是,如果变量 byte-compile-debug 非nil,
错误信息会以 Lisp 错误的形式抛出
(see 错误)。
在打算进行字节编译的文件中编写宏调用时要格外小心。
由于宏调用在编译时展开,因此宏必须已经加载到 Emacs 中,
否则字节编译器无法正确处理。
通常的处理方式是使用 require 表达式,
指定包含所需宏定义的文件(参见see 功能)。
一般情况下,字节编译器不会对正在编译的代码求值,
但它会特殊处理 require 表达式,加载指定的库。
为了避免在用户 运行 编译后的程序时加载宏定义文件,
可以在 require 调用外层使用 eval-when-compile
(参见see 编译时求值)。
更多细节参见see 宏与字节编译。
内联(defsubst)函数则问题较少;
如果你在尚未知晓其定义时就编译对该函数的调用,
调用仍然可以正常工作,只是运行速度会慢一些。
该函数对 symbol 的函数定义进行字节编译,
并用编译后的定义替换原有定义。
symbol 的函数定义必须是函数的实际代码;
byte-compile 不处理函数间接引用。
返回值是字节码函数对象,即 symbol 编译后的定义
(see 闭包函数对象)。
(defun factorial (integer)
"Compute factorial of INTEGER."
(if (= 1 integer) 1
(* integer (factorial (1- integer)))))
⇒ factorial
(byte-compile 'factorial) ⇒ #[257 "\211\300U\203^H^@\300\207\211\301^BS!_\207" [1 factorial] 4 "Compute factorial of INTEGER.\n\n(fn INTEGER)"]
如果 symbol 的定义已经是字节码函数对象,
byte-compile 不做任何操作并返回 nil。
它不会再次编译该符号的定义,因为原始
(未编译)代码已经被字节编译代码替换到符号的函数单元中。
byte-compile 的参数也可以是 lambda 表达式。
此时函数返回对应的编译代码,但不会将其保存到任何地方。
该命令读取光标所在的 defun 形式,对其编译,并对结果求值。 如果你对实际是函数定义的 defun 使用该命令, 效果是安装该函数的编译版本。
compile-defun 通常在回显区显示求值结果,
但如果 arg 非nil,它会将结果
插入到当前缓冲区中被编译形式的后面。
该函数将名为 filename 的 Lisp 代码文件编译为 字节码文件。输出文件名通过将后缀 ‘.el’ 改为 ‘.elc’ 得到; 如果 filename 不以 ‘.el’ 结尾, 则在末尾添加 ‘.elc’。
编译过程是每次读取输入文件中的一个形式。 如果是函数或宏定义,则写入编译后的函数或宏定义。 其他形式会被分批处理,然后每一批被编译并写入, 使得编译后的代码在文件被加载时执行。 读取输入文件时所有注释都会被丢弃。
如果没有错误,该命令返回 t,否则返回 nil。
交互调用时,它会提示输入文件名。
$ ls -l push* -rw-r--r-- 1 lewis lewis 791 Oct 5 20:31 push.el
(byte-compile-file "~/emacs/push.el")
⇒ t
$ ls -l push* -rw-r--r-- 1 lewis lewis 791 Oct 5 20:31 push.el -rw-rw-rw- 1 lewis lewis 638 Oct 8 20:25 push.elc
该命令重新编译 directory(或其子目录)中 所有需要重新编译的 ‘.el’ 文件。 如果存在 ‘.elc’ 文件但比对应的 ‘.el’ 文件旧, 则该文件需要重新编译。
当某个 ‘.el’ 文件没有对应的 ‘.elc’ 文件时,
flag 决定如何处理。
如果为 nil,该命令忽略这些文件。
如果为 0,则编译它们。
如果既不是 nil 也不是 0,
则询问用户是否编译每个此类文件,
并对每个子目录也进行询问。
交互使用时,byte-recompile-directory 会提示输入目录,
flag 为前缀参数。
如果 force 非nil,
该命令会重新编译所有存在 ‘.elc’ 文件的 ‘.el’ 文件。
该命令通常不会编译符号链接指向的 ‘.el’ 文件。
如果可选参数 follow-symlinks 非nil,
则符号链接的 ‘.el’ 文件也会被编译。
返回值不可预测。
该函数对命令行指定的文件运行 byte-compile-file。
该函数只能在 Emacs 的批处理执行中使用,
因为它在完成后会退出 Emacs。
某个文件中的错误不会阻止后续文件的处理,
但该文件不会生成输出文件,
且 Emacs 进程会以非零状态码退出。
如果 noforce 非nil,
该函数不会重新编译那些 ‘.elc’ 文件已是最新的文件。
$ emacs -batch -f batch-byte-compile *.el
当 Emacs 从字节编译文件中加载函数和变量时, 通常不会将它们的文档字符串加载到内存中。 每个文档字符串仅在需要时才从 字节编译文件中动态加载。这样可以节省内存, 并且通过跳过文档字符串的处理加快加载速度。
该特性有一个缺点:如果你删除、移动或修改 编译后的文件(例如编译新版本),Emacs 可能 无法再访问已加载函数或变量的文档字符串。 这类问题通常只在你自行构建 Emacs, 并且恰好编辑和/或重新编译 Lisp 源文件时出现。 要解决此问题,只需在重新编译后重新加载对应文件即可。
对字节编译文件的文档字符串动态加载,
是在编译时为每个字节编译文件确定的。
可以通过选项 byte-compile-dynamic-docstrings 禁用该功能。
如果该变量非 nil,字节编译器会生成
支持文档字符串动态加载的编译文件。
要为特定文件禁用动态加载功能,
请在文件的头部行中将此选项设为 nil
(see Local Variables in Files in The GNU Emacs Manual),示例如下:
-*-byte-compile-dynamic-docstrings: nil;-*-
这主要适用于你预计会修改该文件, 并且希望已加载该文件的 Emacs 会话在文件变更后仍能正常工作的场景。
在内部,文档字符串的动态加载是通过 在编译文件中写入一种特殊的 Lisp 读取构造 ‘#@count’ 实现的。该构造会跳过接下来 count 个字符。它还会使用 ‘#$’ 构造, 该构造表示当前文件的名字(字符串形式)。 不要在 Lisp 源文件中使用这些构造; 它们并非为方便人类阅读而设计。
这些特性允许你编写在程序编译阶段执行的代码。
该形式标记 body 部分,使其在编译包含此代码的文件时执行, 且在运行该代码(无论是否已编译)时也会执行。
你也可以将 body 放入独立文件,再通过 require 引用该文件,
达到类似效果。当 body 内容较多时,推荐使用这种方式。
实际上 require 本身就等效于自动应用了 eval-and-compile,
对应的包会在编译和执行阶段均被加载。
autoload 同样等效于隐式的 eval-and-compile。
编译器在编译时会识别 autoload 定义,
因此调用这类函数不会产生「未定义」警告。
eval-and-compile 的大多数用法都具有较强的专业性:
若某个宏依赖辅助函数构建结果,且该宏既在包内部使用、也对外暴露,
则需通过 eval-and-compile 确保辅助函数在编译和运行阶段均可用;
若函数是通过编程方式定义的(例如使用 fset),
eval-and-compile 可让定义逻辑在编译和运行阶段都执行,
从而使编译器能检查这些函数的调用(并抑制 “未定义(not known to be defined)” 警告)。
该形式标记 body 部分,使其仅在编译阶段执行, 而在加载编译后的程序时不执行。编译器对 body 求值的结果 会作为常量嵌入编译后的程序中。若直接加载源文件(而非编译后文件), 则 body 会按正常流程求值。
若某个常量需要通过计算生成,可使用 eval-when-compile
在编译阶段完成计算。例如:
(defvar gauss-schoolboy-problem (eval-when-compile (apply #'+ (number-sequence 1 100))))
若你使用其他包但仅需其中的宏(字节编译器会展开这些宏),
可通过 eval-when-compile 仅在编译阶段加载该包,
而运行阶段不加载。例如:
(eval-when-compile (require 'my-macro-package))
对于文件内本地定义、且仅在文件内部使用的宏和 defsubst 函数,
也适用此方式:编译文件时需要这些定义,但编译后的文件运行时
通常无需保留。例如:
(eval-when-compile
(unless (fboundp 'some-new-thing)
(defmacro some-new-thing ()
(compatibility code))))
这种写法常用于仅作为兼容性回退的代码,适配不同版本的 Emacs。
Common Lisp 说明: 在顶层作用域中,eval-when-compile
等效于 Common Lisp 中的惯用写法 (eval-when (compile eval) …)。
在其他位置,Common Lisp 的 ‘#.’ 读取宏(解释执行时除外)
更接近 eval-when-compile 的行为。
来自字节编译的错误和警告信息会输出到名为 *Compile-Log* 的缓冲区中。 这些信息包含文件名和行号,用于定位问题所在。 通常用于处理编译器输出的 Emacs 命令也可用于这些信息。
当错误是由程序中非法的语法导致时,字节编译器 可能无法准确判断错误的具体位置。 一种排查方法是切换到缓冲区 *Compiler Input*。 (该缓冲区名以空格开头,因此不会出现在缓冲区菜单中。) 该缓冲区包含正在编译的程序,光标位置 表示字节编译器成功读到的位置; 错误原因通常就在附近。 See 调试无效的 Lisp 语法,了解定位语法错误的一些技巧。
字节编译器最常见的一类警告是针对 被使用但未定义的函数和变量。 这类警告报告的行号是文件末尾, 而非缺失的函数或变量实际被使用的位置; 要找到这些位置,你必须手动搜索文件。
如果你确信某条关于缺失函数或变量的警告是不合理的, 有多种方法可以抑制它:
fboundp 进行条件判断来抑制警告,例如:
(if (fboundp 'func) ...(func ...)...)
对 func 的调用必须位于 if 的 then-form 中,
并且 func 在 fboundp 中必须带引号。
(该特性对 cond 同样有效。)
boundp 进行条件判断来抑制警告:
(if (boundp 'variable) ...variable...)
对 variable 的引用必须位于 if 的 then-form 中,
并且 variable 在 boundp 中必须带引号。
declare-function 告知编译器某个函数已定义。
See 告知编译器某个函数已被定义。
defvar
告知编译器某个变量已定义。
(注意这会将该变量标记为特殊变量,
即动态绑定,但仅在当前词法作用域内有效,
如果在顶层则是整个文件。)
See 定义全局变量。
你还可以使用 with-suppressed-warnings 宏
在指定表达式内抑制编译器警告:
执行时,它等价于 (progn body...),
但编译器不会对 body 中指定的条件发出警告。
warnings 是一个关联列表,
元素为警告符号及其作用的函数/变量符号。
例如,如果你希望调用名为 foo 的废弃函数,
但又想抑制编译警告,可以这样写:
(with-suppressed-warnings ((obsolete foo)) (foo ...))
若要更粗粒度地抑制编译器警告,
可以使用 with-no-warnings 结构:
执行时,它等价于 (progn body...),
但编译器不会对 body 内部的任何内容发出警告。
我们推荐你优先使用 with-suppressed-warnings,
如果确实要使用本结构,请将它包裹在尽可能小的代码片段周围,
以免遗漏除目标警告外的其他有用警告。
通过设置变量 byte-compile-warnings,
可以更精细地控制字节编译器的警告。
详情参见其文档字符串。
有时你可能希望字节编译器将警告以 error 形式报告。
如果需要,将 byte-compile-error-on-warn 设置为非nil。
字节编译函数使用一种特殊的数据类型:闭包。 闭包既用于字节编译的 Lisp 函数,也用于解释执行的 Lisp 函数。 当此类对象作为待调用的函数出现时,Emacs 会使用相应的解释器 来执行字节码或未编译的 Lisp 代码。
在内部实现上,闭包与向量非常相似;
可以使用 aref 访问其元素。
它的打印表示形式也与向量类似,但在左方括号 ‘[’ 前多了一个 ‘#’。
闭包至少包含三个元素,无最大数量限制,但仅有前六个元素有常规用途:
参数描述符。它可以是参数列表(详见 参数列表的特性),
也可以是对所需参数数量进行编码的整数。
若为整数形式:
第 0~6 位表示参数的最小数量;
第 8~14 位表示参数的最大数量;
若参数列表使用 &rest,则第 7 位设为 1;否则为 0。
当闭包是字节码函数时: 若 argdesc 是列表,执行字节码前会对参数进行动态绑定; 若 argdesc 是整数,执行代码前会将参数压入字节码解释器的栈中。
对于解释执行的函数,该元素是构成函数体的(非空)Lisp 形式列表; 对于字节编译的函数,该元素是包含字节码指令的字符串。
对于字节编译的函数,该元素存储字节码引用的 Lisp 对象向量,
包括用作函数名和变量名的符号。
对于解释执行的函数:
若函数使用旧版 Emacs Lisp 的动态作用域方言,该元素为 nil;
否则,该元素存储函数的词法环境。
该函数所需的最大栈空间。此元素对解释执行的函数无实际作用。
文档字符串(若有);否则为 nil。
若文档字符串存储在文件中,该值也可能是数字或列表。
可使用 documentation 函数获取真实的文档字符串(see 访问文档字符串)。
交互规范(若有)。可以是字符串或 Lisp 表达式;
非交互式函数的该元素值为 nil。
以下是字节码函数对象的打印表示示例,对应命令 backward-sexp 的定义:
#[256 "\211\204^G^@\300\262^A\301^A[!\207" [1 forward-sexp] 3 1793299 "^p"]
创建字节码对象的原生方法是使用 make-byte-code:
该函数构造并返回一个闭包,作为以 elements 为元素的字节码函数对象。
请勿自行构造字节码函数的元素——若元素内容不一致, 调用该函数时可能导致 Emacs 崩溃。 应始终交由字节编译器创建这些对象(编译器会保证元素的一致性)。
创建解释执行函数的原生方法是使用 make-interpreted-closure:
该函数构造并返回表示解释执行函数的闭包:
args:函数的参数列表;
body:函数体(必须是非 nil 的 Lisp 形式列表);
env:词法环境(格式与 eval 所用一致,see 求值);
docstring(可选):文档字符串(非 nil 时应为字符串);
iform(可选):交互形式(非 nil 时应为 (interactive arg-descriptor) 格式,see 使用 interactive)。
字节码并非由人工编写,而是交由字节编译器生成。 但我们提供了反汇编器以满足大家的好奇心—— 它能将字节编译后的代码转换为人类可读的形式。
字节码解释器的实现本质是一个简单的栈式虚拟机: 它先将值压入专属栈中,执行计算时再弹出这些值, 计算结果会重新压回栈内。 当字节码函数返回时,会从栈中弹出一个值作为函数的返回值。
除栈外,字节码函数还可通过在变量与栈之间传输值, 来使用、绑定和设置普通的 Lisp 变量。
该命令展示 object 的反汇编代码:
交互调用时,或 buffer-or-name 为 nil/省略时,输出至名为 *Disassemble* 的缓冲区;
若 buffer-or-name 非 nil,则必须是缓冲区或已有缓冲区的名称,此时输出会插入到该缓冲区的光标位置,且光标停留在输出内容前方。
参数 object 可以是:函数名、lambda 表达式(see Lambda 表达式)、字节码对象(see 闭包函数对象)
若为 lambda 表达式,disassemble 会先编译该表达式,再对编译后的代码进行反汇编。
以下是两个使用 disassemble 函数的示例。
我们添加了注释来帮助你关联字节码与 Lisp 源码(这些注释不会出现在 disassemble 的实际输出中):
(defun factorial (integer)
"Compute factorial of an integer."
(if (= 1 integer) 1
(* integer (factorial (1- integer)))))
⇒ factorial
(factorial 4)
⇒ 24
(disassemble 'factorial)
⊣ byte-code for factorial:
doc: Compute factorial of an integer.
args: (arg1)
0 dup ; 获取 integer 的值并
; 压入栈中。
1 constant 1 ; 将 1 压入栈。
2 eqlsign ; 弹出栈顶两个值进行比较, ; 并将比较结果压入栈。
3 goto-if-nil 1 ; 弹出栈顶值并测试;
; 若为 nil,跳转到标号 1,否则继续执行。
6 constant 1 ; 将 1 压入栈顶。
7 return ; 返回栈顶元素。
8:1 dup ; 将integer的值压入栈。 9 constant factorial ; Pushfactorialonto stack. 10 stack-ref 2 ; Push value ofintegeronto stack. 11 sub1 ; 弹出integer,将其值减 1, ; 并将新值压入栈。 12 call 1 ; 调用函数factorial,以栈顶元素为参数; ; 将返回值压入栈。.
13 mult ; 弹出栈顶两个值相乘, ; 并将乘积压入栈。 14 return ; 返回栈顶元素。
silly-loop 函数的反汇编结果稍复杂:
(defun silly-loop (n)
"Return time before and after N iterations of a loop."
(let ((t1 (current-time-string)))
(while (> (setq n (1- n))
0))
(list t1 (current-time-string))))
⇒ silly-loop
(disassemble 'silly-loop)
⊣ byte-code for silly-loop:
doc: Return time before and after N iterations of a loop.
args: (arg1)
0 constant current-time-string ; Push current-time-string
; onto top of stack.
1 call 0 ; Callcurrent-time-stringwith no ; argument, push result onto stack ast1.
2:1 stack-ref 1 ; Get value of the argument n
; and push the value on the stack.
3 sub1 ; Subtract 1 from top of stack.
4 dup ; Duplicate top of stack; i.e., copy the top ; of the stack and push copy onto stack. 5 stack-set 3 ; Pop the top of the stack, ; and setnto the value. ;; (In effect, the sequencedup stack-setcopies the top of ;; the stack into the value ofnwithout popping it.)
7 constant 0 ; Push 0 onto stack. 8 gtr ; Pop top two values off stack, ; test if n is greater than 0 ; and push result onto stack.
9 goto-if-not-nil 1 ; Goto 1 if n > 0
; (this continues the while loop)
; else continue.
12 dup ; Push value oft1onto stack. 13 constant current-time-string ; Pushcurrent-time-string; onto the top of the stack. 14 call 0 ; Callcurrent-time-stringagain.
15 list2 ; Pop top two elements off stack, create a ; list of them, and push it onto stack. 16 return ; Return value of the top of stack.
除了上一章字节编译介绍的字节编译外, Emacs 还可选择性地将 Lisp 函数定义编译为真正的编译代码, 称为本地代码(native code)。该特性依赖 libgccjit 库(属于 GCC 套件), 且要求构建 Emacs 时启用该库支持。 要对 Lisp 代码进行本地编译,系统还必须安装 GCC 和 Binutils(汇编器与链接器)。
要判断当前 Emacs 进程能否生成并加载本地编译的 Lisp 代码,
可调用 native-comp-available-p(see 本地编译函数)。
与字节编译代码不同,本地编译的 Lisp 代码由机器硬件直接执行, 因此能以宿主 CPU 的全速运行。 加速效果通常取决于 Lisp 代码的具体功能, 一般比对应字节编译代码快 **2.5~5 倍**。
由于本地代码在不同系统间通常不兼容, 本地编译代码**无法**在不同机器之间移植, 只能在生成它的同一台机器或高度相似的机器(相同 CPU 与运行时库)上使用。 本地编译代码的可移植性与共享库(.so 或 .dll 文件)一致。
本地编译代码库对 Emacs Lisp 原语(see 什么是函数?) 及其调用约定存在关键依赖, 因此 Emacs 通常无法加载由其他版本 Emacs 生成的本地编译代码。 同一 Lisp 代码经不同版本 Emacs 本地编译后, 通常会生成文件名唯一的本地编译库,仅对应版本 Emacs 可加载。 不过,唯一文件名机制允许同一 Lisp 库经多个 Emacs 版本编译后的库文件共存于同一目录。
文件局部变量 no-byte-compile(see 字节编译)设为非nil 时,
也会同时禁用该文件的本地编译。
此外,类似变量 no-native-compile 可仅禁用本地编译。
若同时指定 no-byte-compile 和 no-native-compile,以前者为准。
有时需要阻止本地编译将结果(*.eln 文件)写入
user-emacs-directory 的子目录(see The Init File)。
可通过修改 native-comp-eln-load-path(see 本地编译变量)
或临时将 HOME 环境变量指向不存在的目录实现。
注意:若 Emacs 需要生成跳板函数(trampolines),后一种方法仍可能产生少量 *.eln 文件——
跳板函数用于本地编译代码中对 Lisp 原语进行 advising 或重定义的场景。
see trampolines。
或者,可使用 startup-redirect-eln-cache 函数
将 *.eln 文件写入非默认目录;see 本地编译函数。
本地编译是作为字节编译的副作用实现的(see 字节编译)。 因此,对 Lisp 代码进行本地编译总是会同时生成其字节码, 所有为字节编译准备 Lisp 代码的规则与注意事项(see 字节编译函数) 对本地编译同样有效。
你可以使用 native-compile 函数
对单个函数或宏定义,或是整个 Lisp 代码文件进行本地编译。
对文件进行本地编译会生成包含本地代码的 .eln 文件。
本地编译可能产生警告或错误信息;
这些信息通常记录在名为 *Native-compile-Log* 的缓冲区中。
在交互式会话中,它使用专用的 LIMPLE 模式(native-comp-limple-mode),
该模式会为此类日志配置合适的 font-lock,其他方面与基本模式一致。
本地编译产生的信息日志可由变量 native-comp-verbose 控制(see 本地编译变量)。
当 Emacs 非交互式运行时,本地编译产生的信息
通过调用 message 输出(see Displaying Messages in the Echo Area),
通常显示在启动 Emacs 的终端的标准错误流中。
该函数将 function-or-file 编译为本地代码。 参数 function-or-file 可以是函数符号、Lisp 形式, 或是包含待编译 Emacs Lisp 源代码的文件名(字符串)。 如果提供可选参数 output,它必须是字符串, 指定用于写入编译代码的文件名。 否则,如果 function-or-file 是函数或 Lisp 形式, 该函数返回编译后的对象; 如果 function-or-file 是文件名, 函数返回为编译代码创建的文件的完整绝对路径。 输出文件默认使用 .eln 扩展名。
该函数会在独立子进程中运行本地编译的最后阶段, 通过 libgccjit 调用 GCC, 子进程使用与调用该函数的 Emacs 相同的可执行文件。
该函数在批处理模式下对 Emacs 命令行指定的文件执行本地编译。
它只能用于 Emacs 的批处理执行,因为编译完成后会退出 Emacs。
如果一个或多个文件编译失败,Emacs 进程会尝试编译所有其他文件,
并以非零状态码退出。
可选参数 for-tarball 非nil 时,
告知函数将生成的 .eln 文件放入
native-comp-eln-load-path 的最后一个目录中(see 库搜索);
这主要用于首次构建 Emacs 源码压缩包的场景,
此时源码压缩包中缺失的本地编译文件应生成在构建目录中,而非用户缓存目录。
本地编译可以完全异步运行,在主 Emacs 进程的子进程中执行。
这使得编译在后台运行时,主 Emacs 进程可正常使用。
当某个 Lisp 文件或字节编译文件没有对应的本地编译版本时,
Emacs 会使用此方法对其进行本地编译。
注意:由于使用子进程,本地编译可能产生字节编译不会出现的警告和错误,
因此 Lisp 代码可能需要修改才能正常工作。
更多细节参见 see 本地编译变量 中的 native-comp-async-report-warnings-errors。
该函数异步编译指定的 files。
参数 files 应为单个文件名(字符串)或一个包含多个文件/目录名的列表。
如果列表中包含目录,可选参数 recursively 应设为非nil,
使编译递归进入这些目录。
如果 load 非nil,Emacs 会加载每个成功编译的文件。
可选参数 selector 用于控制编译哪些 files,可以是以下值之一:
nil 或省略选择 files 中的所有文件和目录。
选择名称匹配该正则表达式的文件和目录。
谓词函数,对 files 中的每个文件和目录调用,
应返回非nil 表示该文件或目录需要被选中编译。
在拥有多个 CPU 执行单元的系统上,当 files 包含多个文件时,
该函数通常会并行启动多个编译子进程,
数量由 native-comp-async-jobs-number 控制(see 本地编译变量)。
此命令将当前缓冲区访问的文件编译为本地代码, 前提是该文件自上次本地编译后已被修改。
此命令与 emacs-lisp-native-compile 类似,
将当前缓冲区访问的文件编译为本地代码,
但编译完成后还会加载该本地代码。
以下函数允许 Lisp 程序在运行时检测本地编译是否可用。
如果运行中的 Emacs 进程内置了本地编译支持,该函数返回非nil。
在动态加载 libgccjit 的系统上,它还会确保该库可用并能被加载。
需要提前知道本地编译是否可用的 Lisp 程序应使用此谓词函数。
默认情况下,异步本地编译将生成的 *.eln 文件
写入 native-comp-eln-load-path 变量指定的第一个可写目录的子目录中(see 本地编译变量)。
你可以在启动文件中使用以下函数修改此行为:
该函数设置异步本地编译将生成的 *.eln 文件写入 cache-directory,
它必须是单个目录(字符串)。
它还会破坏性修改 native-comp-eln-load-path,
使其第一个元素为 cache-directory。
如果 cache-directory 不是绝对路径,
则相对于 user-emacs-directory 解析(see The Init File)。
本节记录控制本地编译行为的变量。
该变量指定本地编译的优化级别。
取值应为 −1 到 3 之间的数字。
0 到 3 之间的值对应编译器命令行选项 -O0、-O1 等的优化级别。
值为 −1 表示禁用本地编译:函数和文件仅进行字节编译;
但仍然会生成 *.eln 文件,只是其中只包含字节码形式的编译代码。
(可以在函数粒度通过 (declare (speed -1)) 形式实现,see declare 形式。)
默认值为 2。
该变量指定生成的本地代码所使用的安全级别。 取值应为数字 0 或 1,含义如下:
如果函数声明与实际功能或调用方式不匹配,且该函数被本地编译, 生成的代码可能行为异常(甚至导致 Emacs 崩溃)。
即使函数声明错误,生成的代码也必须以安全方式生成。
也可以在函数粒度通过 safety 的 declare 形式控制,see declare 形式。
该变量指定本地编译生成的调试信息级别。 取值应为 0~3 的数字,含义如下:
不生成调试输出。默认值。
为本地代码生成调试符号。便于使用 gdb 等调试器调试本地代码。
同 1,并额外输出伪 C 代码。
同 2,并额外输出 GCC 中间过程与 libgccjit 日志文件。
生成的伪 C 代码会存放在对应 .eln 文件所在的同一目录。
该变量通过屏蔽部分或全部日志信息控制本地编译的输出详略。 值为 0(默认)时屏蔽所有日志。 设为 1~3 时,会记录级别高于该值的信息。各值含义:
不记录日志。默认值。
记录代码的最终 LIMPLE 表示。
记录 LAP、最终 LIMPLE 及部分额外过程信息。
最详细模式:记录所有信息。
该变量决定同时启动的本地编译子进程最大数量。 应为非负数。默认值 0,表示使用 CPU 执行单元数量的一半; 若 CPU 只有一个执行单元,则使用 1。
若该变量非nil,异步本地编译子进程产生的警告与错误
会在主 Emacs 会话的 *Warnings* 缓冲区中报告。
默认值 t 表示显示该缓冲区。
若只需记录警告但不弹出 *Warnings*,可将此变量设为 silent。
异步本地编译产生警告的常见原因是:
被编译的文件缺少对某些必需特性的 require。
这些特性可能已加载到主 Emacs 中,
但由于本地编译总是从环境干净的子进程启动,子进程中并不一定存在。
若该变量非nil,退出 Emacs 时会询问是否退出并终止仍在运行的异步本地编译子进程,
避免对应的 .eln 文件写入失败。
若为 nil(默认),Emacs 会直接终止这些子进程而不询问。
变量 native-comp-eln-load-path 保存 Emacs 查找 *.eln 文件的目录列表(see 库搜索);
在这一作用上,它等价于查找 *.el 和 *.elc 文件的 load-path。
该列表中的目录也用于写入异步本地编译生成的 *.eln 文件;
具体来说,Emacs 会将这些文件写入列表中第一个可写目录。
因此,你可以通过修改该变量控制本地编译结果的存放位置。
若该变量非nil,则对 Emacs 加载的、但尚无对应 *.eln 文件的 *.elc 文件
启用异步(也称为即时编译(just-in-time),JIT)本地编译。
该 JIT 编译根据 native-comp-async-jobs-number 的值,
使用批处理模式运行的独立 Emacs 子进程。
当某个 Lisp 文件的 JIT 编译成功完成后,生成的 .eln 文件会被加载,
其代码会替换 .elc 文件提供的函数定义。
将 native-comp-jit-compilation 设为 nil 会禁用 JIT 本地编译。
但即使禁用 JIT 本地编译,Emacs 仍可能需要启动异步本地编译子进程来生成跳板函数(trampolines)。
控制这一行为请使用下面的独立变量。
该变量控制跳板函数的生成。
跳板函数是一小段本地代码,用于在 native-comp-speed 设为 2 或更高时,
让本地编译的 Lisp 代码能够调用被 advising 或重定义的 Lisp 原语。
Emacs 将生成的跳板函数存放在独立的 *.eln 文件中。
默认情况下,该变量值为 t,允许生成跳板文件;
设为 nil 则禁用生成。
注意:如果某个原语所需的跳板函数不存在且无法生成,
从本地编译 Lisp 代码对该原语的调用会忽略重定义与 advising,
行为如同直接从 C 调用原语。
因此,不建议禁用跳板函数生成,除非你确信所有 Lisp 程序所需的跳板函数
都已编译并对 Emacs 可访问。
该变量的值也可以是字符串,此时它指定一个目录名,
用于存放生成的跳板函数 *.eln 文件,
覆盖 native-comp-eln-load-path 中的目录。
这在你希望按需生成跳板函数、但又不想将其存放在用户 HOME
或其他公共 *.eln 目录时非常有用。
但与 native-comp-eln-load-path 中的目录不同,
跳板函数会直接存放在该变量指定的目录中,而非其版本子目录。
若该目录名不是绝对路径,则相对于 invocation-directory 解析(see Operating System Environment)。
若该变量非nil,且 Emacs 需要生成跳板函数但找不到可写目录,
则会将其存放在 temporary-file-directory 中(see 生成唯一文件名)。
在找不到可写目录或该变量为字符串时生成的跳板函数, 仅在当前 Emacs 会话期间有效,因为 Emacs 不会在这些位置搜索跳板函数。
有多种方法可以查找和分析 Emacs Lisp 程序中的问题。
trace-function-foreground
和 trace-function-background,以及用于将指定变量的值加入跟踪的
trace-values。详细信息请查看 trace.el 中这些功能的文档。
用于调试输入输出问题的其他实用工具包括日志文件(see Terminal Input)
和 open-termscript 函数(see Terminal Output)。
标准的Lisp 调试器(Lisp debugger)可以暂停表达式的求值。 在求值暂停状态(通常称为断点(break))下,你可以查看运行时栈、 检查局部或全局变量的值,也可以修改这些值。 由于断点属于递归编辑,Emacs 的所有常规编辑功能都可用; 你甚至可以运行会递归进入调试器的程序。See 递归编辑。
进入调试器最重要的时机是在 Lisp 错误发生时。 这让你可以调查错误的直接原因。
但是,进入调试器并不是错误的常规处理方式。
很多命令在被不当调用时会触发 Lisp 错误,
在普通编辑中,每次都进入调试器会非常不便。
因此,如果你希望错误触发调试器,请将变量 debug-on-error
设为非nil。
(命令 toggle-debug-on-error 提供了简便的切换方式。)
注意,由于技术原因,本节定义的功能无法用于调试 重绘代码所调用的 Lisp 中的错误。 相关帮助请见 See 调试重绘错误。
该变量决定在错误被触发且未被处理时是否调用调试器。
如果 debug-on-error 为 t,
除了 debug-ignored-errors(见下文)中列出的错误外,
所有类型的错误都会调用调试器。
如果为 nil,则所有错误都不会进入调试器。
该值也可以是一个错误条件列表(see 如何发出错误信号)。
此时只有列表中的错误条件才会调用调试器
(同样排除 debug-ignored-errors 中的错误)。
例如,将 debug-on-error 设置为列表 (void-variable),
则调试器只会在变量无值的错误时被调用。
注意,在某些情况下 eval-expression-debug-on-error
会覆盖本变量;见下文。
当该变量为非nil 时,Emacs 不会在进程过滤函数和哨兵函数
外围创建错误处理器。因此这些函数中的错误也会触发调试器。See Processes。
该变量指定无论 debug-on-error 取何值
都**不**进入调试器的错误。
其值为错误条件符号和/或正则表达式的列表。
如果错误具有其中任一条件符号,或错误信息匹配任一正则表达式,
则该错误不会进入调试器。
该变量的默认值包含 user-error,
以及一些编辑中经常出现但很少由 Lisp 程序漏洞导致的错误。
但“很少”不等于“从不”;
如果你的程序触发了匹配此列表的错误,
你可以尝试修改此列表来调试该错误。
最简单的方法通常是将 debug-ignored-errors 设为 nil。
如果该变量为非nil(默认值),
运行命令 eval-expression 时会临时将 debug-on-error 绑定为 t。
See Evaluating Emacs Lisp Expressions in The GNU Emacs Manual。
如果 eval-expression-debug-on-error 为 nil,
则在 eval-expression 执行期间不会改变 debug-on-error 的值。
通常情况下,被 condition-case 捕获的错误永远不会触发调试器。
condition-case 会在调试器之前获得处理错误的机会。
如果你将 debug-on-signal 设为非nil,
则无论是否存在 condition-case,
调试器都会优先获得所有错误的处理机会。
(要触发调试器,错误仍需满足 debug-on-error
和 debug-ignored-errors 指定的条件。)
例如,设置该变量有助于从 emacsclient 的 --eval 选项
所执行的代码中获取调用栈。
如果该变量为非nil,emacsclient 执行的 Lisp 代码触发错误时,
调用栈会在运行中的 Emacs 中弹出。
警告: 将该变量设为非nil 可能产生烦人的效果。
Emacs 的很多部分在正常运行时会捕获错误,
你甚至可能意识不到那里发生了错误。
如果你需要调试被 condition-case 包裹的代码,
可以考虑使用 condition-case-unless-debug(see 编写处理错误的代码)。
如果你将 debug-on-event 设置为某个特殊事件(see 特殊事件),
Emacs 会在收到该事件时立即尝试进入调试器,
绕过 special-event-map。
目前仅支持对应信号 SIGUSR1 和 SIGUSR2 的值(这是默认值)。
当 inhibit-quit 被设置且 Emacs 无其他响应时,该功能很有用。
如果你将 debug-on-message 设置为正则表达式,
当 Emacs 在回显区显示匹配该表达式的消息时,会进入调试器。
例如,在查找某条消息的产生原因时很有用。
你可以在 ‘*Backtrace*’ 缓冲区中使用 e 命令
对当前栈帧中的表达式求值,在使用 Edebug 时
也可以用 e 和 C-x C-e 做类似操作。
默认情况下,这些命令会抑制调试器(因为此时重新进入调试器
通常会让你脱离当前调试上下文)。
将 debug-allow-recursive-debug 设为非nil
可以允许这些命令递归进入调试器。
要调试启动文件加载过程中发生的错误,
请使用选项 ‘--debug-init’。
它会在加载启动文件期间将 debug-on-error 绑定为 t,
并绕过通常会捕获启动文件错误的 condition-case。
由于技术原因,当重绘过程调用的 Lisp 代码发生错误时, Emacs 常规的调试机制无法使用。 本节介绍如何从这类错误中获取调用栈,这对调试此类错误有帮助。
这些方法适用于以下场景中使用的 Lisp 形式:
例如 :eval 模式行结构(see 模式行的数据结构),
以及所有从重绘过程调用的钩子,包括:
fontification-functions (see Automatic Face Assignment).
window-scroll-functions (see Hooks for Window Scrolling and Changes).
注意:如果重绘调用的钩子函数中发生错误,
错误处理机制可能会将该函数从钩子中移除。
因此你需要以某种方式重新初始化该钩子(例如使用 add-hook),
才能重现该问题。
要在此类场景下生成调用栈,需将变量 backtrace-on-redisplay-error
设为非nil。错误发生时,Emacs 会将调用栈输出到
*Redisplay-trace* 缓冲区,但不会自动在窗口中显示该缓冲区。
这样做是为了避免不必要地破坏你正在调试的重绘过程。
你需要手动显示该缓冲区,例如使用命令
switch-to-buffer-other-frame(C-x 5 b)。
将该变量设为非nil,可在重绘调用的任意 Lisp 代码发生错误时
生成调用栈。
当程序陷入无限循环且无法返回时,首先需要停止该循环。 在大多数操作系统中,你可以使用 C-g 触发退出(quit)。 See 退出。
常规的退出操作无法提供程序陷入循环的原因。
要获取更多信息,可将变量 debug-on-quit 设为非nil。
当调试器在无限循环中启动后,你可以使用单步命令继续调试。
如果逐步执行完整个循环,你可能会获得足够的信息来解决问题。
使用 C-g 退出不被视为错误,
debug-on-error 对 C-g 的处理无影响。
同理,debug-on-quit 对错误也无影响。
该变量决定在 quit 信号被触发且未被处理时是否调用调试器。
如果 debug-on-quit 为非nil,
则每次退出(即按下 C-g)都会调用调试器。
如果 debug-on-quit 为 nil(默认值),
退出时不会调用调试器。
要排查程序执行过程中出现的问题,一种实用技巧是: 当某个特定函数被调用时自动进入调试器。 你可以为发生问题的函数设置该断点,然后单步执行该函数; 也可以为问题发生前不久调用的函数设置断点, 快速跳过该函数调用后,再单步执行其调用者。
该函数设置 function-name 每次被调用时都触发调试器。
任何以 Lisp 代码定义的函数或宏(无论解释执行还是编译执行) 都可设置入口断点。如果该函数是命令, 则无论是从 Lisp 调用还是交互式调用(读取参数后),都会进入调试器。 你也可以为原语函数(即 C 语言编写的函数)设置入口断点, 但仅当原语函数被 Lisp 代码调用时生效。 特殊形式不允许设置入口断点。
以交互方式调用 debug-on-entry 时,
会在迷你缓冲区中提示输入 function-name。
如果该函数已设置入口断点,debug-on-entry 不执行任何操作。
该函数始终返回 function-name。
以下示例演示该函数的用法:
(defun fact (n)
(if (zerop n) 1
(* n (fact (1- n)))))
⇒ fact
(debug-on-entry 'fact)
⇒ fact
(fact 3)
------ Buffer: *Backtrace* ------ Debugger entered--entering a function: * fact(3) eval((fact 3)) eval-last-sexp-1(nil) eval-last-sexp(nil) call-interactively(eval-last-sexp) ------ Buffer: *Backtrace* ------
该函数取消 function-name 上由 debug-on-entry 设置的断点。
以交互方式调用时,会在迷你缓冲区中提示输入 function-name。
如果省略 function-name 或设为 nil,
则取消所有函数的入口断点。
如果指定函数未设置入口断点,调用该函数无任何效果。
有时函数出现问题是因为变量被错误赋值。 设置为每当变量被修改时就触发调试器,是快速找到赋值源头的方法。
该函数设置每当 variable 被修改时就调用调试器。
它基于观察点(watchpoint)机制实现,因此继承相同特性与限制: 变量的所有别名会被一同观察,仅能观察动态变量, 且无法检测变量所引用对象内部的修改。 详情见 变量改变时运行函数。
该函数取消 variable 上由 debug-on-variable-change 设置的断点。
交互调用时,会在迷你缓冲区提示输入变量名。
若 variable 被省略或为 nil,则取消所有变量的修改断点。
对未设置修改断点的变量,该函数无任何效果。
你可以在程序的指定位置写入表达式 (debug),使调试器在该处被调用。
操作方法:打开源文件,在合适位置插入 ‘(debug)’,
然后按 C-M-x(eval-defun,Lisp 模式下的按键绑定)。
警告: 若仅为临时调试,请务必在保存文件前撤销此次插入!
插入 ‘(debug)’ 的位置必须是可以额外求值且可忽略其值的地方。
(如果 (debug) 的值没有被忽略,将会改变程序的执行流程!)
最常见的合适位置是在 progn 或隐式 progn 内部。see 顺序执行。
如果你不确定要在源码的哪个位置插入调试语句,
但希望在显示某条特定消息时展示调用栈,
可以将 debug-on-message 设置为匹配该消息的正则表达式。
进入调试器时,它会在一个窗口显示之前选中的缓冲区, 在另一个窗口显示名为 *Backtrace* 的缓冲区。 调用栈缓冲区的每一行对应当前正在执行的一层 Lisp 函数。 缓冲区开头会有一条消息,说明调试器被触发的原因 (若是因错误触发,则包含错误信息与相关数据)。
调用栈缓冲区为只读,并使用专用主模式——调试器模式(Debugger mode),
其中字母按键被定义为调试器命令。
常规的 Emacs 编辑命令仍然可用;
因此你可以切换窗口,查看出错时正在编辑的缓冲区、切换缓冲区、访问文件或进行其他编辑操作。
但调试器属于递归编辑层级(see 递归编辑),
建议使用完毕后回到调用栈缓冲区并退出调试器(使用 q 命令)。
退出调试器会离开递归编辑状态,并隐藏调用栈缓冲区。
(你可以通过设置变量 debugger-bury-or-kill 自定义 q 对调用栈缓冲区的行为。
例如,将其设为 kill 以直接杀死缓冲区而非隐藏。更多选项请查阅该变量文档。)
进入调试器后,debug-on-error 会根据 eval-expression-debug-on-error 被临时设置。
若后者为非 nil,则 debug-on-error 会被临时设为 t。
但调试期间发生的后续错误(默认)不会再次触发调试器,
因为 inhibit-debugger 也会被绑定为非 nil。
调试器本身必须以字节编译形式运行,因为它对 Lisp 解释器的状态有特定假设。 若调试器以解释形式运行,这些假设将不成立。
调试器模式派生自调用栈模式(Backtrace mode), 该模式也被 Edebug 和 ERT 用于显示调用栈。see Edebug,the ERT manual in ERT: Emacs Lisp Regression Testing。
调用栈缓冲区展示正在执行的函数及其参数值。 创建时,每个栈帧占一行(可能很长)。 (栈帧是 Lisp 解释器记录某一次函数调用信息的位置。) 最近调用的函数位于最上方。
在调用栈中,你可以将光标移到某行以指定对应栈帧。 光标所在行的栈帧称为当前栈帧(current frame)。
如果函数名带有下划线,表示 Emacs 知道其源码位置。
你可以用鼠标点击该名称,或将光标移到该处按 RET 访问源码。
即使名称没有下划线,你也可以按 RET,
若存在帮助信息,则会在帮助缓冲区中显示该符号的说明。
绑定到 M-. 的 xref-find-definitions 命令
也可用于调用栈中的任意标识符。see Looking Up Identifiers in The GNU Emacs Manual。
在调用栈中,长列表、长字符串、长向量、长结构体的尾部,
以及深度嵌套的对象会显示为带下划线的 “...”。
你可以用鼠标点击 “...”,或将光标移到该处按 RET 以显示被隐藏的部分。
可通过自定义 backtrace-line-length 控制缩写程度。
以下是用于导航和查看调用栈的命令列表:
切换显示当前栈帧的局部变量。
跳转到当前栈帧开头,或上一栈帧开头。
跳转到下一栈帧开头。
为光标处的顶层 Lisp 表达式添加换行与缩进,提高可读性。
将光标处的顶层 Lisp 表达式折叠为单行。
切换光标所在栈帧的 print-circle。
切换光标所在栈帧的 print-gensym。
展开光标所在栈帧中所有被缩写为 “...” 的表达式。
调试器缓冲区(处于调试器模式下)除了提供常规的 Emacs 命令 以及上一节介绍的调用栈模式命令外,还提供专用命令。 调试器命令最重要的用途是单步执行代码,以便观察控制流如何流转。 调试器可以单步执行**解释型函数**的控制结构,但无法对字节编译函数执行此操作。 如果你希望单步调试字节编译函数,请将其替换为同一函数的解释版定义。 (操作方法:打开该函数的源码,在其定义上按 C-M-x。) 你无法使用 Lisp 调试器单步执行原语函数。
部分调试器命令作用于**当前栈帧**。 如果某个栈帧以星号开头,表示退出该栈帧时会再次进入调试器。 这对查看函数的返回值非常有用。
以下是调试器模式的命令列表:
退出调试器并继续执行。 这将恢复程序执行,仿佛从未进入过调试器(不包括你在调试器内部修改变量值或数据结构带来的副作用)。
继续执行,但在下一次调用任意 Lisp 函数时进入调试器。 这使你可以单步执行表达式的子表达式,查看子表达式计算出的值以及它们的其他行为。
以这种方式触发调试器的函数调用所创建的栈帧会被自动标记, 以便退出该栈帧时再次调用调试器。 你可以使用 u 命令取消此标记。
标记当前栈帧,使退出该栈帧时进入调试器。 以这种方式标记的栈帧在调用栈缓冲区中会显示星号。
退出当前栈帧时不进入调试器。 这会取消对该栈帧执行的 b 命令。 直观效果是调用栈缓冲区中对应行的星号消失。
像 b 一样标记当前栈帧,
然后像 c 一样继续执行,但临时禁用所有通过 debug-on-entry
设置了入口断点的函数的断点。
在迷你缓冲区读取一个 Lisp 表达式,
在相关词法环境中(如适用)对其求值,并在回显区打印结果。
调试器在运行时会修改某些重要变量与当前缓冲区;
e 会临时恢复它们在调试器外部的值,以便你检查和修改。
这让调试器更加透明。
相比之下,M-: 在调试器中无特殊处理,直接显示调试器内部的变量值。
默认情况下,该命令在求值期间会抑制调试器,避免被求值表达式中的错误在原有错误之上叠加新错误。
将用户选项 debug-allow-recursive-debug 设为非nil 可覆盖此行为。
与 e 类似,但同时将求值结果保存到 *Debugger-record* 缓冲区。
终止正在调试的程序,返回到顶层 Emacs 命令执行。
如果调试器是因 C-g 进入,但你只想退出而非调试,请使用 q 命令。
从调试器返回一个值。 该值通过在迷你缓冲区读取表达式并求值得到。
当调试器因退出 Lisp 调用栈帧(通过 b 请求或用 d 进入该帧)而被调用时,
r 命令非常有用;此时 r 命令指定的值会作为该栈帧的返回值。
如果你调用了 debug 并使用其返回值,该命令也很有用。
其他情况下,r 与 c 效果相同,指定的返回值无效。
调试器因错误进入时,无法使用 r。
显示设置了调用时触发调试器的函数列表。
即通过 debug-on-entry 设置了入口断点的函数。
本节详细介绍用于调用调试器的 debug 函数。
该函数进入调试器。
在交互式会话中,它会切换到名为 *Backtrace* 的缓冲区
(如果是递归进入调试器的第二次调用,则为 *Backtrace*<2>,依此类推),
并填充 Lisp 函数调用栈的相关信息。
随后进入递归编辑状态,以调试器模式显示调用栈缓冲区。
在批处理模式下(更一般地,当 noninteractive 为非nil 时,see Batch Mode),
该函数会在标准错误流中显示 Lisp 调用栈,
然后终止 Emacs 并使其以非零退出码退出(see Killing Emacs)。
将 backtrace-on-error-noninteractive 绑定为 nil 可抑制批处理模式下的调用栈输出,详见下文。
调试器模式的 c、d、j 和 r 命令会退出递归编辑;
之后 debug 切换回之前的缓冲区,并返回到调用 debug 的位置。
这是 debug 函数唯一能返回给调用者的方式。
debugger-args 参数的作用是:debug 会将剩余参数显示在 *Backtrace* 缓冲区顶部,供用户查看。
除下文所述情况外,这是这些参数的**唯一**用途。
但 debug 的第一个参数若为特定值,则具有特殊含义。
(通常这些值仅由 Emacs 内部使用,而非程序员调用 debug 时使用。)
以下是这些特殊值的说明:
lambda ¶第一个参数为 lambda 表示:
因 debug-on-next-call 为非nil,在进入某个函数时调用了 debug。
调试器会在缓冲区顶部显示一行文本:‘调试器进入--进入函数:(Debugger entered--entering a function:)’。
debug第一个参数为 debug 表示:
因进入了设置了入口断点的函数,调用了 debug。
调试器会像 lambda 情况一样显示字符串 ‘调试器进入--进入函数:(Debugger entered--entering a function:)’,
同时标记该函数的栈帧,使其在退出时触发调试器。
t第一个参数为 t 表示:
因 debug-on-next-call 为非nil,在求值某个函数调用表达式时调用了 debug。
调试器会在缓冲区顶部显示:‘调试器进入--开始求值函数调用表达式:(Debugger entered--beginning evaluation of function call form:)’。
exit第一个参数为 exit 表示:
退出之前标记为“退出时触发调试器”的栈帧时调用了 debug。
此时 debug 的第二个参数是该栈帧要返回的值。
调试器会在缓冲区顶部显示 ‘调试器进入--返回值:(Debugger entered--returning value:)’,后跟要返回的值。
error ¶第一个参数为 error 表示:
因错误或 quit 信号被触发且未被处理,进入调试器。
调试器会显示 ‘调试器进入--Lisp 错误:(Debugger entered--Lisp error:)’,
后跟触发的错误及 signal 的所有参数。例如:
(let ((debug-on-error t)) (/ 1 0))
------ Buffer: *Backtrace* ------ Debugger entered--Lisp error: (arith-error) /(1 0) ... ------ Buffer: *Backtrace* ------
若触发的是错误信号,通常 debug-on-error 为非nil;
若触发的是 quit 信号,通常 debug-on-quit 为非nil。
nil当你希望显式进入调试器时,可将 debugger-args 的第一个参数设为 nil。
剩余的 debugger-args 会打印在缓冲区首行。
你可利用此特性显示自定义消息——例如,提醒自己调用 debug 的触发条件。
该变量默认值为非nil,表示批处理模式下进入调试器时会显示 Lisp 函数调用栈。
将该变量绑定为 nil 会抑制调用栈输出,仅显示错误消息。
本节介绍调试器内部使用的函数和变量。
该变量的值是用于调用调试器的函数。
其值必须是接受任意数量参数的函数,或更常见的是函数名。
该函数应触发某种调试器。变量的默认值为 debug。
Lisp 传递给该函数的第一个参数表示调用原因。
参数的约定在 debug 的说明中有详细描述(see 调用调试器)。
该函数打印当前活跃的 Lisp 函数调用跟踪信息。
输出的跟踪信息与 debug 在 *Backtrace* 缓冲区中显示的内容完全相同。
函数的返回值始终为 nil。
以下示例中,Lisp 表达式显式调用 backtrace。
这会将调用栈打印到流 standard-output,
本示例中该流对应缓冲区 ‘backtrace-output’。
调用栈的每一行代表一次函数调用。 如果函数的所有参数值均已确定,该行会显示函数名及参数值列表; 如果参数仍在计算中,该行则显示包含函数及其未求值参数的列表。 长列表或深度嵌套的结构可能会被省略。
(with-output-to-temp-buffer "backtrace-output"
(let ((var 1))
(save-excursion
(setq var (eval '(progn
(1+ var)
(list 'testing (backtrace))))))))
⇒ (testing nil)
----------- Buffer: backtrace-output ------------ backtrace() (list 'testing (backtrace))
(progn ...) eval((progn (1+ var) (list 'testing (backtrace)))) (setq ...) (save-excursion ...) (let ...) (with-output-to-temp-buffer ...) eval((with-output-to-temp-buffer ...)) eval-last-sexp-1(nil)
eval-last-sexp(nil) call-interactively(eval-last-sexp) ----------- Buffer: backtrace-output ------------
若该变量为非nil,调用栈中的每个栈帧都会以列表形式显示。
此举旨在提升调用栈的可读性,但代价是特殊形式与常规函数调用在视觉上不再有区别。
当 debugger-stack-frame-as-list 为非nil 时,上述示例的输出如下:
----------- Buffer: backtrace-output ------------ (backtrace) (list 'testing (backtrace))
(progn ...) (eval (progn (1+ var) (list 'testing (backtrace)))) (setq ...) (save-excursion ...) (let ...) (with-output-to-temp-buffer ...) (eval (with-output-to-temp-buffer ...)) (eval-last-sexp-1 nil)
(eval-last-sexp nil) (call-interactively eval-last-sexp) ----------- Buffer: backtrace-output ------------
若该变量为非nil,表示在下一次调用 eval、apply 或 funcall 前调用调试器。
进入调试器后,该变量 debug-on-next-call 会被设为 nil。
调试器中的 d 命令正是通过设置该变量实现功能。
该函数设置调用栈中向下数 level 层的栈帧的“退出时调试”标志,将其值设为 flag。
若 flag 为非nil,该栈帧后续退出时会触发调试器。
即使通过该栈帧进行非本地退出,也会进入调试器。
该函数仅由调试器内部使用。
该变量记录当前交互式命令的调试状态。
每次交互式调用命令时,该变量会被绑定为 nil。
调试器可设置该变量,为同一命令调用期间后续的调试器触发留存信息。
使用该变量而非普通全局变量的优势在于: 其数据不会延续到后续的命令调用中。
该变量已废弃,将在未来版本中移除。
函数 backtrace-frame 专为 Lisp 调试器设计使用。
它返回调用栈中向下数 frame-number 层的栈帧的计算状态信息。
如果该栈帧尚未求参数值,或属于特殊形式,返回值为 (nil function arg-forms…)。
如果该栈帧已完成参数求值并调用了函数,返回值为 (t function arg-values…)。
返回值中,function 是被求值列表的 CAR 部分,
若是宏调用则为 lambda 表达式。
如果函数包含 &rest 参数,该参数会表示为 arg-values 列表的尾部。
若指定了 base,则 frame-number 相对于 function 为 base 的最顶层栈帧计数。
若 frame-number 超出范围,backtrace-frame 返回 nil。
函数 mapbacktrace 会为调用栈中的每个栈帧调用一次 function,
起始位置为 function 等于 base 的第一个栈帧
(若省略 base 或其值为 nil,则从栈顶开始)。
调用 function 时传入四个参数:evald、func、args 和 flags。
如果栈帧尚未求参数值或属于特殊形式,evald 为 nil,args 为表达式列表。
如果栈帧已完成参数求值并调用了函数,evald 为 t,args 为值列表。
flags 是当前栈帧属性的属性列表(plist):
目前仅支持 :debug-on-exit 属性,
若栈帧的“退出时调试”标志已设置,则该属性值为 t。
Edebug 是适用于 Emacs Lisp 程序的源码级调试器,使用它你可以:
下面前三节内容足以让你开始使用 Edebug。
要使用 Edebug 调试 Lisp 程序,必须先对需要调试的 Lisp 代码进行 插桩(instrument)。
一种简单的方法是:将光标移到函数或宏的定义内部,然后按 C-u C-M-x(带前缀参数的 eval-defun)。
其他插桩方式见 Edebug 的代码插桩。
函数被插桩后,任何对该函数的调用都会激活 Edebug。 根据你选择的 Edebug 运行模式,激活 Edebug 可能会暂停执行并允许单步调试, 也可能只刷新显示并继续执行,同时监听调试命令。 默认运行模式为单步模式(step),会暂停执行。See Edebug 运行模式。
在 Edebug 中,你通常会看到一个显示正在调试的 Lisp 源码的 Emacs 缓冲区, 称为 源码缓冲区(source code buffer),它暂时为只读状态。
左侧边缘的箭头指示函数当前正在执行的行。 光标初始时指向该行内函数正在执行的具体位置,但如果你手动移动光标,这一对应关系就不再成立。
如果你对下面的 fac 函数定义进行插桩,然后执行 (fac 3),
通常会看到如下显示。光标位于 if 前面的左括号处:
(defun fac (n)
=>∗(if (< 0 n)
(* n (fac (1- n)))
1))
函数内部 Edebug 可以暂停执行的位置称为 暂停点(stop points)。
每个列表子表达式的前后,以及每个变量引用之后,都会设置暂停点。
下面用点号标出 fac 函数中的暂停点:
(defun fac (n)
.(if .(< 0 n.).
.(* n. .(fac .(1- n.).).).
1).)
源码缓冲区中除了 Emacs Lisp 模式的命令外,还可以使用 Edebug 的专用命令。
例如,输入 Edebug 命令 SPC 可以执行到下一个暂停点。
进入 fac 后按一次 SPC,显示如下:
(defun fac (n)
=>(if ∗(< 0 n)
(* n (fac (1- n)))
1))
当 Edebug 在某个表达式执行后暂停时,会在回显区显示该表达式的值。
其他常用命令:b 在暂停点设置断点,g 执行到断点处, q 退出 Edebug 并返回顶层命令循环。 输入 ? 可显示所有 Edebug 命令列表。
要使用 Edebug 调试 Lisp 代码,必须先对代码 插桩(instrument)。 插桩会在代码中插入额外逻辑,以便在合适位置调用 Edebug。
在函数定义上使用前缀参数执行 C-M-x(eval-defun),
会在求值前先对定义进行插桩。(这不会修改源码本身。)
如果变量 edebug-all-defs 为非nil,则反转前缀参数的含义:
此时 C-M-x 默认会插桩, 除非 带有前缀参数。
edebug-all-defs 默认值为 nil。
命令 M-x edebug-all-defs 可切换该变量的值。
如果 edebug-all-defs 为非nil,
则 eval-region 和 eval-buffer 在求值时也会对定义插桩。
类似地,edebug-all-forms 控制 eval-region 是否对 所有 表达式插桩,包括非定义表达式。
这不适用于加载或迷你缓冲区中的求值。
命令 M-x edebug-all-forms 可切换该选项。
另一个命令 M-x edebug-eval-top-level-form
可对任意顶层表达式插桩,不受 edebug-all-defs 和 edebug-all-forms 影响。
edebug-defun 是 edebug-eval-top-level-form 的别名。
当 Edebug 处于激活状态时,命令 I(edebug-instrument-callee)
可对光标所在列表表达式调用的函数或宏进行插桩(如果尚未插桩)。
这仅在 Edebug 能找到该函数源码时有效;
因此,加载 Edebug 后,eval-region 会记录它所求值的每个定义的位置,即使没有插桩。
另见命令 i(see 跳转),它会在插桩后直接进入该调用。
Edebug 知道如何对所有标准特殊形式、带表达式参数的 interactive 形式、
匿名 lambda 表达式以及其他定义形式进行插桩。
但 Edebug 无法自行判断用户定义宏会如何处理宏调用的参数,
因此你必须通过 Edebug 规范提供相关信息;详情见 see Edebug 和 宏。
当 Edebug 在会话中第一次准备插桩代码时,会运行钩子 edebug-setup-hook,
然后将其设为 nil。
你可以用它来加载与你正在使用的包相关的 Edebug 规范,且只在使用 Edebug 时加载。
如果 Edebug 在插桩时检测到语法错误,会将光标停在出错代码处并抛出 invalid-read-syntax 错误。
例如:
error→ Invalid read syntax: "Expected lambda expression"
插桩失败的一个可能原因是:某些宏定义 Emacs 尚未加载。 解决方法是先加载定义了待插桩函数的文件。
要移除定义上的插桩,只需以**不插桩**的方式重新求值该定义。
有两种求值方式永远不会插桩:
使用 load 从文件加载,以及使用迷你缓冲区的 eval-expression(M-:)。
另一种移除插桩的方法是使用命令 edebug-remove-instrumentation。
它也可以移除所有已插桩代码的插桩状态。
更多 Edebug 内部可用的求值函数见 See 表达式求值。
Edebug 支持多种运行被调试程序的方式,这些方式称为 Edebug 运行模式(Edebug execution modes),不要与主模式或次要模式混淆。 当前 Edebug 运行模式决定了 Edebug 在暂停前会连续执行多少代码(例如,是在每个暂停点都停下,还是直接运行到下一个断点),以及在暂停前显示多少求值进度。
通常,你通过输入命令以指定模式继续运行程序,从而选择 Edebug 运行模式。 下表列出这些命令,除 S 外,其余都会恢复程序执行(至少会向前执行一段)。
停止:不再继续执行程序,等待更多 Edebug 命令(edebug-stop)。
单步:在下一个遇到的暂停点停止(edebug-step-mode)。
下一步:在某个表达式之后的下一个暂停点停止(edebug-next-mode)。
另见 跳转 中的 edebug-forward-sexp。
跟踪:在每个 Edebug 暂停点短暂暂停(默认为 1 秒,edebug-trace-mode)。
快速跟踪:在每个暂停点刷新显示,但不实际暂停(edebug-Trace-fast-mode)。
运行:一直执行到下一个断点(edebug-go-mode)。See Edebug 断点。
持续:在每个断点处暂停 1 秒,然后继续(edebug-continue-mode)。
快速持续:将光标跳转到每个断点,但不暂停(edebug-Continue-fast-mode)。
无间断运行:忽略所有断点(edebug-Go-nonstop-mode)。
你仍可以通过输入 S 或任意编辑命令停止程序。
一般来说,表中靠前的运行模式会让程序执行更慢、暂停更早,靠后的模式则执行更快、暂停更晚。
当进入新的 Edebug 层级时,Edebug 通常会在遇到第一个被插桩的函数时暂停。
如果你希望只在断点处暂停,或完全不暂停(例如收集覆盖度数据时),
可以将 edebug-initial-mode 从默认的 step 改为 go、Go-nonstop 或其他可选值(see Edebug 选项)。
可以直接使用 C-x C-a C-m(edebug-set-initial-mode)进行设置:
该命令绑定在 C-x C-a C-m,用于设置 edebug-initial-mode。
它会提示你输入一个按键以指定模式,输入上表中的 8 个按键之一即可设置对应模式。
注意,同一个 Edebug 层级可能被多次重新进入,例如某个被插桩的函数被同一条命令多次调用时。
在执行或跟踪过程中,你可以输入任意 Edebug 命令中断执行。 Edebug 会在下一个暂停点停止程序,然后执行你输入的命令。 例如,在执行期间输入 t 会在下一个暂停点切换到跟踪模式。 可以用 S 直接停止执行,不做其他操作。
如果你的函数恰好需要读取输入,你原本想用来中断执行的字符可能会被函数当作输入读取。 留意程序何时需要输入,可以避免这类意外情况。
包含本节命令的键盘宏无法完全正常工作:退出 Edebug 恢复程序时,会丢失键盘宏的状态。这一问题不易修复。
此外,在 Edebug 外部定义或执行键盘宏不会影响 Edebug 内部的命令,这通常是有益的。
另见 Edebug 选项 中的 edebug-continue-kbd-macro 选项。
该选项指定在跟踪模式或持续模式下,每步执行之间等待的秒数。默认值为 1 秒。
本节介绍的命令会一直执行,直到到达指定位置才暂停。 除 i 外,这些命令都会先创建一个临时断点,确定暂停位置,然后切换到运行模式。 在到达目标暂停点之前遇到的任何其他断点,同样会使程序暂停。 关于断点的详细说明,见 See Edebug 断点。
如果发生非本地退出,这些命令可能无法按预期工作,因为非本地退出会跳过你期望程序暂停的临时断点。
执行到光标附近的暂停点(edebug-goto-here)。
执行一个表达式后暂停(edebug-forward-sexp)。
执行到当前所在表达式的末尾(edebug-step-out)。
单步进入光标所在列表表达式调用的函数或宏(edebug-step-in)。
h 命令通过临时断点,执行到光标当前位置或之后的暂停点。
f 命令让程序向前执行一个表达式。
更精确地说,它在 forward-sexp 会到达的位置设置一个临时断点,然后以运行模式执行,使程序在断点处暂停。
如果使用前缀参数 n,临时断点会被设置在光标之后第 n 个表达式处。 如果当前所在列表在到达 n 个元素前就结束,则暂停位置为当前所在表达式之后。
你必须确认 forward-sexp 找到的位置是程序真正会执行到的位置。
例如在 cond 表达式中,情况可能并非如此。
为了更灵活,f 命令从光标位置而非当前暂停点开始执行 forward-sexp。
如果你希望 从当前暂停点 执行一个表达式,先输入 w(edebug-where)将光标移到暂停点,再输入 f。
o 命令会执行出当前表达式。它在包含光标的表达式末尾设置临时断点。 如果当前所在表达式本身是函数定义,o 会执行到定义中最后一个表达式之前。 如果当前位置就在那里,它会从函数返回后暂停。 换句话说,除非你位于最后一个表达式之后,否则该命令不会退出当前正在执行的函数。
通常,h、f 和 o 命令会显示“Break”,并在显示刚求值的表达式结果前暂停 edebug-sit-for-seconds 秒。
将 edebug-sit-on-break 设置为 nil 可以取消该暂停。See Edebug 选项。
i 命令单步进入光标所在列表表达式调用的函数或宏,并在其第一个暂停点暂停。 注意,该表达式不一定是即将被求值的表达式。 但如果该表达式是即将被求值的函数调用,记得在参数被求值前使用该命令,否则就来不及了。
i 命令会对即将进入的函数或宏进行插桩(如果尚未插桩)。 这很方便,但要注意:除非你显式移除插桩,否则该函数或宏会一直保持插桩状态。
本节介绍 Edebug 的其他一些命令。
显示 Edebug 帮助信息(edebug-help)。
退出一层递归编辑,返回上一层命令(abort-recursive-edit)。
返回顶层编辑器命令循环(top-level)。
这会退出所有递归编辑层级,包括所有层级的 Edebug。
但是,被 unwind-protect 或 condition-case 保护的插桩代码可能会恢复调试。
与 q 类似,但即使是被保护的代码也不再暂停(edebug-top-level-nonstop)。
在回显区重新显示最近一次的表达式结果(edebug-previous-result)。
显示调用栈,为清晰起见排除 Edebug 自身的函数(edebug-pop-to-backtrace)。
关于调用栈及其操作命令,见 See 调用栈。
如果希望在调用栈中显示 Edebug 自身的函数, 使用 M-x edebug-backtrace-show-instrumentation。 再次隐藏则使用 M-x edebug-backtrace-hide-instrumentation。
如果调用栈帧以 ‘>’ 开头,表示 Edebug 知道该栈帧对应的源码位置。 使用 s 跳转到当前栈帧对应的源码。
当你继续执行时,调用栈缓冲区会被自动关闭。
你可以在 Edebug 中调用命令,从而递归地再次激活 Edebug。 只要 Edebug 处于激活状态,你就可以用 q 退出到顶层,或用 C-] 退出一层递归编辑。 你可以用 d 显示所有待求值的调用栈。
Edebug 的单步模式会在到达下一个暂停点时暂停执行。 一旦开始执行,还有三种方式可以暂停 Edebug: 断点、全局中断条件和源码断点。
在使用 Edebug 时,你可以在测试程序中指定 断点(breakpoints):即执行时应当暂停的位置。 你可以在任意暂停点设置断点,暂停点的定义见 使用 Edebug。 设置与取消断点时,受影响的暂停点是源码缓冲区中光标所在位置或之后的第一个暂停点。 以下是 Edebug 中用于断点操作的命令:
在光标所在位置或之后的暂停点设置断点(edebug-set-breakpoint)。
若使用前缀参数,则为临时断点 — 第一次使程序暂停后便自动失效。
断点处会显示带有 edebug-enabled-breakpoint 或 edebug-disabled-breakpoint 外观的覆盖层。
取消光标所在位置或之后的暂停点的断点(如果有)(edebug-unset-breakpoint)。
取消当前表达式中的所有断点(edebug-unset-breakpoints)。
切换光标附近断点的启用/禁用状态(edebug-toggle-disable-breakpoint)。
该命令主要用于条件断点,避免重新设置条件的麻烦。
设置条件断点,仅当 condition 表达式求值结果为非nil 时才暂停程序(edebug-set-conditional-breakpoint)。
使用前缀参数则为临时断点。
将光标移动到当前定义中的下一个断点(edebug-next-breakpoint)。
在 Edebug 中,你可以用 b 设置断点,用 u 取消断点。 先将光标移到目标 Edebug 暂停点,再按 b 或 u 即可在该处设置或取消断点。 在未设置断点的位置执行取消操作无效果。
重新求值或重新插桩一个定义会清除该定义上之前的所有断点。
条件断点(conditional breakpoint) 会在程序每次到达时检测一个条件。
条件求值过程中发生的任何错误都会被忽略,视为结果为 nil。
设置条件断点请使用 x,并在迷你缓冲区中指定条件表达式。
如果在已存在条件断点的暂停点再次设置,迷你缓冲区会显示之前的表达式供你编辑。
使用带前缀参数的设置命令,可以将条件断点或无条件断点设为 临时断点(temporary)。 当临时断点触发暂停后,会自动被取消。
除了在“无间断运行”模式下,Edebug 总会在断点处停止或暂停。 在该模式下,断点会被完全忽略。
使用 B 命令可以查看断点位置:它会将光标移到同一函数内光标之后的下一个断点; 如果后面没有断点,则回到第一个断点。该命令不会继续执行,仅在缓冲区中移动光标。
全局中断条件(global break condition) 会在指定条件满足时暂停执行,无论发生在何处。
Edebug 会在每个暂停点对全局中断条件求值;
若结果为非nil,程序会根据运行模式停止或暂停,如同触发了断点。
若条件求值发生错误,则不会暂停。
条件表达式保存在 edebug-global-break-condition 中。
当 Edebug 激活时,可在源码缓冲区使用 X 命令指定新表达式;
只要 Edebug 已加载,任何缓冲区随时都可使用 C-x X X(edebug-set-global-break-condition)。
全局中断条件是查找代码中某事件发生位置最简单的方法,但会显著降低运行速度。
因此不使用时应将条件重置为 nil。
每次重新插桩一个定义时,其中的所有断点都会被清除。
如果你希望设置不会被清除的断点,可以编写**源码断点**:
即在源码中直接调用函数 edebug。
当然你可以将该调用写成条件形式。
例如在 fac 函数中,可以插入下面一行,使参数为 0 时暂停:
(defun fac (n)
(if (= n 0) (edebug))
(if (< 0 n)
(* n (fac (1- n)))
1))
当 fac 定义被插桩且函数被调用时,对 edebug 的调用就相当于一个断点。
根据运行模式,Edebug 会在该处停止或暂停。
如果调用 edebug 时没有正在执行被插桩的代码,该函数会转而调用 debug。
当 Emacs 触发错误且未通过 condition-case 处理时,通常会显示错误信息。
当 Edebug 处于激活状态并执行插桩代码时,它会默认响应所有未处理的错误。
你可以通过选项 edebug-on-error 和 edebug-on-quit 自定义这一行为,见 Edebug 选项。
当 Edebug 响应错误时,会定位到错误发生前最后一个暂停点。 该位置可能是某个未插桩函数的调用点,而错误实际发生在该函数内部。 对于未绑定变量错误,最后一个已知暂停点可能距离出错的变量引用很远。 这种情况下,你可能需要显示完整调用栈(see Edebug 其他命令)。
如果在 Edebug 激活期间修改了 debug-on-error 或 debug-on-quit,
这些修改会在 Edebug 退出后失效。
此外,在 Edebug 的递归编辑期间,这些变量会被绑定为进入 Edebug 之前的值。
下列 Edebug 命令可以查看进入 Edebug 之前的缓冲区和窗口状态。 外部窗口配置是指 Edebug 外部生效的窗口布局及内容。
切换到查看外部窗口配置(edebug-view-outside)。
按 C-x X w 返回 Edebug。
临时显示外部当前缓冲区,并将光标定位到外部位置(edebug-bounce-point),
暂停 1 秒后返回 Edebug。
使用前缀参数 n 则暂停 n 秒。
将光标移回源码缓冲区中当前暂停点(edebug-where)。
如果你在显示同一缓冲区的其他窗口中使用该命令, 后续显示当前定义时将优先使用该窗口。
切换 Edebug 是否保存并恢复外部窗口配置(edebug-toggle-save-windows)。
使用前缀参数时,W 仅切换是否保存和恢复选中窗口。 若要指定不显示源码缓冲区的窗口,必须使用全局键映射中的 C-x X W。
你可以使用 v 查看外部窗口配置,或仅用 p 临时跳转到当前缓冲区的外部光标位置,即使它通常不显示。
移动光标后,你可能希望跳回暂停点。 在源码缓冲区中可以用 w 实现; 从任意缓冲区跳回源码缓冲区的暂停点可使用 C-x X w。
每次使用 W 关闭保存功能时,Edebug 会清除已保存的外部窗口配置; 因此即使重新打开保存功能,下次退出 Edebug(继续执行程序)时当前窗口布局也不会改变。 但是,除非打开足够多的窗口,否则 *edebug* 和 *edebug-trace* 的自动刷新可能会覆盖你希望查看的缓冲区。
在 Edebug 内部,你可以像 Edebug 未运行时一样求值表达式。 Edebug 会尽量对表达式的求值和打印保持“不可见”。 会产生副作用的表达式将按预期执行,除非修改的是 Edebug 显式保存和恢复的数据。 关于该过程的细节,See 外部环境。
在 Edebug 外部的上下文中求值表达式 exp(edebug-eval-expression)。
也就是说,Edebug 会尽量减少对求值过程的干扰。
结果会显示在回显区;如果该命令带前缀参数,则会弹出新缓冲区并对结果进行美观打印。
默认情况下,该命令在求值期间会抑制调试器,避免被求值表达式中的错误在现有错误之上再叠加一层。
将用户选项 debug-allow-recursive-debug 设置为非nil 可以取消这一行为。
在 Edebug 自身的上下文中求值表达式 exp(eval-expression)。
在 Edebug 外部的上下文中求值光标前的表达式(edebug-eval-last-sexp)。
使用前缀参数 0(C-u 0 C-x C-e)时,不截断长内容(如字符串和列表)。
其他前缀参数会将值在独立缓冲区中美观打印。
Edebug 支持对包含词法绑定符号的表达式求值,这些符号由 cl.el 中的以下结构创建:
lexical-let、macrolet 和 symbol-macrolet。
你可以使用名为 *edebug* 的**求值列表缓冲区 交互式求值表达式(evaluation list buffer)。 你还可以设置一组 求值列表(evaluation list),让这些表达式在 Edebug 每次刷新显示时自动求值。
切换到求值列表缓冲区 *edebug*(edebug-visit-eval-list)。
在 *edebug* 缓冲区中,你可以使用 Lisp Interaction 模式的命令(see Lisp Interaction in The GNU Emacs Manual)以及以下专用命令:
在外部上下文中求值光标前的表达式,并将值插入缓冲区(edebug-eval-print-last-sexp)。
使用前缀参数 0(C-u 0 C-j)时,不截断长内容(如字符串和列表)。
在 Edebug 外部的上下文中求值光标前的表达式(edebug-eval-last-sexp)。
根据缓冲区内容重建新的求值列表(edebug-update-eval-list)。
删除光标所在的求值列表组(edebug-delete-eval-item)。
切回源码缓冲区并定位到当前暂停点(edebug-where)。
你可以在求值列表窗口中用 C-j 或 C-x C-e 求值表达式,就像在 *scratch* 中一样; 但它们是在 Edebug 外部的上下文中求值的。
你交互式输入的表达式(及其结果)会在继续执行时丢失; 但你可以设置一个 求值列表(evaluation list),让其中的表达式在每次执行暂停时都被求值。
要实现这一点,请在求值列表缓冲区中写入一个或多个 求值列表组(evaluation list groups)。 一个求值列表组由一个或多个 Lisp 表达式组成,组与组之间用注释行分隔。
命令 C-c C-u(edebug-update-eval-list)会重建求值列表,扫描缓冲区并使用每个组的第一个表达式。
(设计思路是:组内第二个表达式是之前计算并显示的结果。)
每次进入 Edebug 时,都会重新显示求值列表:将每个表达式插入缓冲区,后面跟上其当前值。 它还会插入注释行,使每个表达式自成一组。 因此,如果你在不修改缓冲区内容的情况下再次输入 C-c C-u,求值列表实际上不会改变。
如果从求值列表中求值时发生错误,错误信息会以字符串形式显示,就像它是结果一样。 因此,使用当前无效变量的表达式不会中断你的调试过程。
下面是求值列表窗口在添加多个表达式后的示例:
(current-buffer) #<buffer *scratch*> ;--------------------------------------------------------------- (selected-window) #<window 16 on *scratch*> ;--------------------------------------------------------------- (point) 196 ;--------------------------------------------------------------- bad-var "Symbol's value as variable is void: bad-var" ;--------------------------------------------------------------- (recursion-depth) 0 ;--------------------------------------------------------------- this-command eval-last-sexp ;---------------------------------------------------------------
要删除一个组,将光标移入其中并输入 C-c C-d, 或者直接删除该组的文本,再用 C-c C-u 更新求值列表。 要向求值列表添加新表达式,将表达式插入合适位置,新建一行注释,然后输入 C-c C-u。 你不必在注释行中输入横线——其内容无关紧要。
选中 *edebug* 后,你可以用 C-c C-w 返回源码缓冲区。 *edebug* 缓冲区会在你继续执行时被关闭,并在下次需要时重新创建。
如果程序中的表达式生成的值包含循环列表结构,Edebug 尝试打印该值时可能会报错。
处理循环结构的一种方法是设置 print-length 或 print-level 来截断打印内容。
Edebug 会自动帮你完成这一操作:
它会将 print-length 和 print-level 绑定为变量 edebug-print-length 和 edebug-print-level 的值(只要这些值为非nil)。
详见 See 影响输出的变量。
若值为非nil,Edebug 在打印结果时会将 print-length 绑定为此值。默认值为 50。
若值为非nil,Edebug 在打印结果时会将 print-level 绑定为此值。默认值为 50。
你也可以将 print-circle 绑定为非nil 值,
从而更清晰地打印循环结构和包含共享元素的结构。
以下是创建循环结构的代码示例:
(setq a (list 'x 'y)) (setcar a a)
如果 print-circle 为非nil,打印函数(如 prin1)会将 a 打印为 ‘#1=(#1# y)’。
其中 ‘#1=’ 标记其后的结构为标签 ‘1’,而 ‘#1#’ 则引用此前标记的该结构。
这种标记法也适用于列表或向量中所有共享的元素。
若值为非nil,Edebug 在打印结果时会将 print-circle 绑定为此值。默认值为 t。
关于如何自定义打印行为的更多细节,见 see 输出函数。
Edebug 可以记录执行跟踪信息,并将其存储在名为 *edebug-trace* 的缓冲区中。
该缓冲区是函数调用与返回的日志,包含函数名、参数及返回值。
将 edebug-trace 设置为非nil 值即可启用跟踪记录。
创建跟踪缓冲区与使用跟踪执行模式(see Edebug 运行模式)并非同一概念。
启用跟踪记录后,每次函数进入和退出都会向跟踪缓冲区添加行。 函数进入记录以 ‘::::{’ 开头,后跟函数名和参数值; 函数退出记录以 ‘::::}’ 开头,后跟函数名和函数返回结果。
记录中 ‘:’ 的数量表示递归深度。 你可以通过跟踪缓冲区中的大括号找到函数调用对应的开始和结束位置。
你可以通过重新定义函数 edebug-print-trace-before 和 edebug-print-trace-after,
自定义函数进入和退出时的跟踪记录行为。
该宏请求在 body 表达式执行前后记录额外的跟踪信息。
参数 string 指定要添加到跟踪缓冲区中 ‘{’ 或 ‘}’ 后的文本。
所有参数都会被求值,edebug-tracing 返回 body 中最后一个表达式的值。
该函数向跟踪缓冲区插入文本。
文本内容通过 (apply 'format format-string format-args) 计算得出,
并自动追加换行符以分隔不同记录。
无论 Edebug 是否激活,调用 edebug-tracing 和 edebug-trace 时都会向跟踪缓冲区插入行。
向跟踪缓冲区添加文本时,其对应的窗口也会自动滚动以显示最新插入的行。
Edebug 提供基础的覆盖度测试与执行次数统计显示功能。
覆盖度测试通过对比每个表达式的当前结果与上一次结果来工作: 在当前 Emacs 会话中开始覆盖度测试后,如果某个表达式返回过两种不同的值,就认为该表达式已被覆盖。 因此,要对你的程序进行覆盖度测试,需要在多种条件下运行它,并观察行为是否正确; 当你尝试了足够多的不同条件,使得每个表达式都返回过两种不同的值时,Edebug 会提示你。
覆盖度测试会降低执行速度,因此只有在 edebug-test-coverage 为非nil 时才会启用。
无论是否启用覆盖度测试,也无论运行模式是否为无间断运行,被插桩函数的所有执行过程都会进行执行次数统计。
使用 C-x X =(edebug-display-freq-count)显示当前定义的覆盖信息与执行次数统计。
直接按 =(edebug-temp-display-freq-count)则临时显示相同信息,直到按下下一个按键。
该命令显示当前定义中每一行代码的执行次数统计数据。
它会在每行代码后以注释行形式插入执行次数。你可以用一次 undo 撤销所有插入。
次数会显示在表达式前的左括号 ‘(’、表达式后的右括号 ‘)’ 下方,或变量的最后一个字符下方。
为简化显示,如果某表达式的次数与同一行上更早表达式的次数相同,则不重复显示。
表达式次数后面的字符 ‘=’ 表示:该表达式每次求值都返回相同的值。 换句话说,从覆盖度测试角度看,它尚未被覆盖。
要清除某个定义的执行次数与覆盖度数据,只需使用 eval-defun 重新插桩即可。
例如,在设置源码断点并执行 (fac 5),且将 edebug-test-coverage 设置为 t 后,
当断点触发时,执行次数数据如下所示:
(defun fac (n)
(if (= n 0) (edebug))
;#6 1 = =5
(if (< 0 n)
;#5 =
(* n (fac (1- n)))
;# 5 0
1))
;# 0
这些注释行表明 fac 被调用了 6 次。
第一个 if 语句返回了 5 次,且每次结果都相同;
第二个 if 的判断条件也是如此。
对 fac 的递归调用则完全没有返回。
Edebug 尽量对被调试程序保持透明,但无法完全做到。 当你使用 e 或求值列表缓冲区求值表达式时,Edebug 也会通过临时恢复外部环境来保持透明。 本节精确说明 Edebug 恢复哪些环境,以及在哪些方面无法做到完全透明。
每当进入 Edebug 时,在决定是否生成跟踪信息或暂停程序之前,都需要先保存并恢复某些数据。
max-lisp-eval-depth(see 求值)会被增大,以降低 Edebug 对栈的影响。
但在使用 Edebug 时,你仍然可能出现栈空间不足的情况。
如果 Edebug 在对包含非常大引用列表的代码进行插桩时达到递归深度限制,你也可以增大 edebug-max-depth 的值。
edebug-continue-kbd-macro 为非nil,否则 executing-kbd-macro 会被绑定为 nil。
当 Edebug 需要显示内容时(例如在跟踪模式下),会保存来自 Edebug 外部的当前窗口配置(see Window Configurations)。 退出 Edebug 时,会恢复之前的窗口配置。
Emacs 仅在暂停时才会刷新显示。通常,当你继续执行后,程序会在断点处或单步后重新进入 Edebug,期间不会暂停或读取输入。 在这种情况下,Emacs 没有机会刷新外部窗口配置。 因此,你看到的将与上一次 Edebug 激活时相同的窗口配置,不会被打断。
为显示内容而进入 Edebug 时,还会保存并恢复以下数据(但如果发生错误或退出信号,其中部分数据会被故意不恢复)。
edebug-save-windows 为非nil,外部窗口配置会被保存和恢复(see Edebug 选项)。
如果 edebug-save-windows 的值是一个列表,则只保存和恢复列表中的窗口。
窗口配置在出错或退出时不会被恢复,
但即使出错或退出,外部选中窗口仍会被重新选中,以防 save-excursion 处于激活状态。
不过,源码缓冲区的窗口起始位置与水平滚动状态不会被恢复,以保证 Edebug 内部显示的一致性。
保存和恢复外部窗口配置有时会改变你正在调试的 Lisp 程序所操作的缓冲区中的光标位置,尤其是当你的程序会移动光标时。
如果这种情况影响了调试,建议将 edebug-save-windows 设置为 nil(see Edebug 选项)。
edebug-save-displayed-buffer-points 为非nil,每个已显示缓冲区中的光标位置会被保存和恢复。
overlay-arrow-position 和 overlay-arrow-string 会被保存和恢复,
因此你可以在同一缓冲区的其他位置的递归编辑中安全地调用 Edebug。
cursor-in-echo-area 被局部绑定为 nil,使光标显示在窗口中。
当 Edebug 被进入并真正从用户读取命令时,会保存(并在之后恢复)这些额外数据:
last-command、this-command、last-command-event、last-input-event、
last-event-frame、last-nonmenu-event 以及 track-mouse。
Edebug 内部的命令不会影响这些变量在 Edebug 外部的值。
在 Edebug 内部执行命令可能会改变 this-command-keys 将要返回的按键序列,
而无法从 Lisp 中重置该按键序列。
Edebug 无法保存和恢复 unread-command-events 的值。
在该变量拥有非空值时进入 Edebug,可能会干扰被调试程序的执行。
command-history 中。
极少数情况下,这可能会改变执行行为。
standard-output 和 standard-input 会被 recursive-edit 绑定为 nil,
但 Edebug 在求值期间会临时恢复它们。
defining-kbd-macro 被绑定为 edebug-continue-kbd-macro。
要让 Edebug 正确地对调用宏的表达式进行插桩,需要额外的处理。本小节将详细说明相关细节。
当 Edebug 对调用 Lisp 宏的表达式进行插桩时,需要该宏的额外信息才能正确完成工作。 这是因为无法仅凭宏调用本身判断其哪些子表达式是需要求值的形式(求值可能发生在宏体内部、宏展开结果求值时,或后续任意时机)。
因此,你必须为 Edebug 可能遇到的每个宏定义 Edebug 规范,以说明该宏调用的格式。
实现方式是在宏定义中添加 debug 声明。以下是为 for 示例宏指定规范的简单例子(see 宏参数的重复求值问题):
(defmacro for (var from init to final do &rest body) "Execute a simple \"for\" loop. For example, (for i from 1 to 10 do (print i))." (declare (debug (symbolp "from" form "to" form "do" &rest form))) ...)
Edebug 规范用于标识宏调用中哪些部分是需要求值的表达式。
对于简单宏,规范通常与宏定义的形参列表非常相似,但规范的表达能力远强于宏参数。
关于 declare 形式的更多说明见 See 定义宏。
请注意确保在插桩代码时,Edebug 能够识别对应的规范。
如果要插桩的函数使用了定义在其他文件中的宏,你可能需要先求值该函数所在文件中的 require 形式,
或显式加载包含该宏的文件。如果宏定义被 eval-when-compile 包裹,你可能需要手动求值该定义。
你也可以通过 def-edebug-spec 为宏单独定义 Edebug 规范,而不依赖宏定义本身。
对于 Lisp 编写的宏定义,添加 debug 声明是更推荐、更便捷的方式;
但 def-edebug-spec 使得为 C 实现的特殊形式定义 Edebug 规范成为可能。
指定宏 macro 调用中的哪些表达式是需要求值的形式。 specification 应为 Edebug 规范,两个参数均不求值。
参数 macro 实际上可以是任意符号,不限于宏名。
以下表格列出 specification 的可选类型,以及每种类型对参数处理方式的说明:
t所有参数均被插桩以支持求值。这是 (body) 的简写形式。
该符号必须具有 Edebug 规范,Edebug 会使用该规范替代当前符号。 这种间接引用会持续到找到其他类型的规范为止,允许你从其他宏继承规范。
列表元素描述调用形式中各参数的类型。规范列表的可选元素将在后续章节说明。
如果一个宏既没有通过 debug 声明,也没有通过 def-edebug-spec 调用定义 Edebug 规范,
则变量 edebug-eval-macro-args 将生效:
该变量控制 Edebug 处理无显式规范的宏参数的方式。
若值为 nil(默认),则不对任何参数进行求值插桩;否则,所有参数都会被插桩。
如果宏调用的部分参数会被求值,而另一部分不会,则 Edebug 规范必须使用 规范列表(specification list)。
规范列表中的某些元素匹配一个或多个参数,另一些则会修改其后所有元素的处理方式。
后者被称为 规范关键字(specification keywords),是以 ‘&’ 开头的符号(例如 &optional)。
规范列表可以包含子列表,用于匹配本身就是列表的参数;也可以包含用于分组的向量。 子列表和分组将规范列表划分为多层级结构。规范关键字仅对其所在子列表或分组中的剩余元素生效。
当规范列表包含多选或重复结构时,与实际宏调用进行匹配可能需要**回溯**。 更多细节见 see 规范中的回溯。
Edebug 规范具备正则表达式匹配的能力,外加一些上下文无关文法结构: 匹配括号平衡的子列表、对表达式的递归处理,以及通过间接规范实现的递归。
下表是规范列表中可使用的元素及其含义(相关示例见 see 规范示例):
sexp单个不求值的 Lisp 对象,不进行插桩。
如果宏在宏展开时对某个参数求值,应当为该参数使用 sexp 而非 form。
form单个会被求值的表达式,会被插桩。
如果你的宏在表达式求值前用 lambda 包裹它,请改用 def-form。见下方 def-form。
place广义变量。See 广义变量。
body&rest form 的简写。见下方 &rest。
如果你的宏在代码体求值前用 lambda 包裹它,请改用 def-body。见下方 def-body。
lambda-expr未被引用的 lambda 表达式。
&optional规范列表中此后的所有元素均为可选;一旦某个元素不匹配,Edebug 就在当前层级停止匹配。
若只需让部分元素可选,后面跟随必选元素,可使用 [&optional specs…]。
若要指定多个元素要么全部匹配、要么全都不匹配,可使用 &optional [specs…]。
参见 defun 示例。
&rest规范列表中此后的所有元素可以重复零次或多次。 但在最后一次重复时,即使表达式提前结束而未能匹配所有元素,也不算错误。
若只需让部分元素重复,可使用 [&rest specs…]。
若要指定每次重复时多个元素都必须全部匹配,可使用 &rest [specs…]。
&or规范列表中此后的每个元素都是一个候选项。
必须匹配其中一个,否则 &or 规范失败。
&or 后的每个列表元素都是一个独立候选项。
若要将多个列表元素作为一个候选项,可用 […] 包裹。
¬此后的每个元素都按类似 &or 的方式作为候选项匹配,
但只要有一个匹配,规范就失败;
如果全都不匹配,则虽不匹配任何内容,但 ¬ 规范成功。
&define表明该规范用于定义型表达式。 Edebug 对定义型表达式的定义是:包含一个或多个代码表达式, 这些代码会被保存并在定义型表达式执行之后才运行。
定义型表达式本身不会被插桩(即 Edebug 不会在其前后暂停),
但其内部的表达式通常会被插桩。
&define 关键字应当作为列表规范的第一个元素。
nil在当前参数列表层级没有更多参数可匹配时成功,否则失败。 参见子列表规范和反引号示例。
gate ¶不匹配任何参数,但在匹配当前层级剩余规范时,禁止通过 gate 回溯。
主要用于生成更精确的语法错误信息。
详情见 规范中的回溯,另见 let 示例。
&error&error 后需跟随一个字符串作为错误信息;
它会中止插桩,并在迷你缓冲区显示该信息。
&interpose由一个函数控制剩余代码的解析。
形式为 &interpose spec fun args...,
表示 Edebug 先用 spec 匹配代码,
然后以匹配到的代码、解析函数 pf 以及 args... 为参数调用 fun。
解析函数接受一个参数,指定用于解析剩余代码的规范列表,必须被精确调用一次,
并返回 fun 应当返回的插桩后代码。
例如 (&interpose symbolp pcase--match-pat-args) 匹配首元素为符号的表达式,
然后由 pcase--match-pat-args 根据该头部符号查找对应的规范,
并传给它收到的解析函数 pf。
other-symbol ¶规范列表中的其他符号可以是谓词或间接规范。
如果该符号已有 Edebug 规范,这个**间接规范**可以是一个列表规范(用于替换该符号),
或是一个用于处理参数的函数。
该规范可用 def-edebug-elem-spec 定义:
定义用于替换符号 element 的规范 specification, specification 必须是列表。
否则,该符号应当是一个谓词。
谓词会以当前参数为参数被调用,若返回 nil,则规范失败,该参数不插桩。
常用谓词包括 symbolp、integerp、stringp、vectorp 和 atom。
[elements…] ¶由元素组成的向量将这些元素归为一个 分组规范(group specification)。 其含义与向量本身无关。
"string"参数必须是名为 string 的符号。
等价于引号符号 'symbol(符号名为 string),但推荐使用字符串形式。
(vector elements…)参数必须是向量,且其元素匹配规范中的 elements。 参见反引号示例。
(elements…)其他普通列表为 子列表规范(sublist specification),参数必须是列表,且其元素匹配规范 elements。
子列表规范可以是点分列表,对应的参数列表也可以是点分列表。
或者,点分列表规范的最后一个 CDR 可以是另一个子列表规范
(通过分组或间接规范,例如 (spec . [(more specs…)])),
其元素匹配非点分列表的参数。
这在递归规范中非常有用,如反引号示例。
关于终止此类递归,参见上面 nil 规范的说明。
注意,写成 (specs . nil) 的子列表规范等价于 (specs),
而 (specs . (sublist-elements…)) 等价于 (specs sublist-elements…)。
下面是仅可出现在 &define 之后的附加规范列表。参见 defun 示例。
&name从代码中提取当前定义型表达式的名称。
形式为 &name [prestring] spec [poststring] fun args...,
表示 Edebug 先用 spec 匹配代码,
然后以当前名称、args...、prestring、匹配到的代码和 poststring 拼接后的结果为参数调用 fun。
若 fun 省略,则默认使用拼接函数(在旧名称与新名称之间用 @ 连接)。
name参数是一个符号,作为定义型表达式的名称。
是 [&name symbolp] 的简写。
定义型表达式不要求必须有名称字段,也可以有多个名称字段。
arg参数是一个符号,作为定义型表达式的参数名。 但 lambda 列表关键字(以 ‘&’ 开头的符号)不允许使用。
lambda-list ¶匹配一个 lambda 列表,即 lambda 表达式的参数列表。
def-body参数是定义中的代码体。
与上面的 body 类似,但定义体必须用另一个 Edebug 调用进行插桩,
以查找与该定义关联的信息。
对定义中最高层级的表达式列表使用 def-body。
def-form参数是定义中单个最高层级的表达式。
与 def-body 类似,但用于匹配单个表达式而非表达式列表。
作为特殊情况,def-form 还表示该表达式执行时不输出跟踪信息。
参见 interactive 示例。
如果规范在某一处匹配失败,并不一定意味着会报语法错误; 相反,会发生 回溯(backtracking),直到所有候选项都尝试完毕。 最终,参数列表中的每一个元素都必须被规范中的某个元素匹配, 且规范中所有必选元素都必须匹配到某个参数。
当检测到语法错误时,可能要等到很久之后才会报告——
即在更上层的候选项都耗尽之后,此时光标位置也已经远离真正的错误位置。
但如果在错误发生时禁用回溯,就可以立即报告错误。
注意,在以下几种情况下回溯会被自动重新启用:
当通过 &optional、&rest 或 &or 建立新的候选项时,
或是开始处理子列表、分组、间接规范时。
启用或禁用回溯的效果,仅限于当前正在处理的层级的剩余部分以及更低层级。
在匹配任何表达式类规范(即 form、body、def-form 和 def-body)时,回溯会被禁用。
这些规范可以匹配任意表达式,因此任何错误一定出在表达式本身,而不在更高层级。
在成功匹配带引号的符号、字符串规范或 &define 关键字之后,回溯也会被禁用,
因为这通常表示已经匹配到一个可识别的结构。
但如果你有多组候选项结构都以同一个符号开头,
通常可以将该符号从候选项中提取出来以绕过这一限制,例如:
["foo" &or [first case] [second case] ...]。
这两种自动禁用回溯的方式可以满足大多数需求,
但偶尔使用 gate 规范显式禁用回溯会很有用。
当你确定更高层不会再有其他候选项可以匹配时,这就非常实用。
参见 let 规范的示例。
通过研究下面的示例,能更容易理解 Edebug 规范。
假设有一个宏 my-test-generator,用于对提供的数据列表执行测试。
虽然由 edebug-eval-macro-args 控制(see 宏调用插桩),
Edebug 默认不会将参数当作代码插桩,但显式说明这些参数是数据会更清晰:
(def-edebug-spec my-test-generator (&rest sexp))
特殊形式 let 包含一系列绑定和一个代码体。
每个绑定可以是一个符号,或是一个包含符号与可选表达式的子列表。
在下面的规范中,注意子列表内部的 gate,用于在找到子列表后禁止回溯。
(def-edebug-spec let
((&rest
&or symbolp (gate symbolp &optional form))
body))
Edebug 为 defun 及其关联的参数列表和 interactive 规范使用下面的定义。
必须特殊处理 interactive 形式,因为它的表达式参数实际在函数体之外求值。
(defmacro 的规范与 defun 非常相似,只是多支持 declare 语句。)
(def-edebug-spec defun
(&define name lambda-list
[&optional stringp] ; Match the doc string, if present.
[&optional ("interactive" interactive)]
def-body))
(def-edebug-elem-spec 'lambda-list
'(([&rest arg]
[&optional ["&optional" arg &rest arg]]
&optional ["&rest" arg]
)))
(def-edebug-elem-spec 'interactive
'(&optional &or stringp def-form)) ; Notice: def-form
下面的反引号规范展示了如何匹配点分列表,以及如何用 nil 终止递归。
它还展示了如何匹配向量的各个成分。
(Edebug 实际定义的规范略有不同,并不支持点分列表,因为那样会导致可能失败的深层递归。)
(def-edebug-spec \` (backquote-form)) ; Alias just for clarity.
(def-edebug-elem-spec 'backquote-form
'(&or ([&or "," ",@"] &or ("quote" backquote-form) form)
(backquote-form . [&or nil backquote-form])
(vector &rest backquote-form)
sexp))
这些选项会影响 Edebug 的行为:
在使用 Edebug 之前调用的函数。
每次设置为新值时,Edebug 会调用这些函数一次,然后将 edebug-setup-hook 重置为 nil。
你可以用它来加载与某个包相关的 Edebug 规范,但仅在同时使用 Edebug 时才加载。
See Edebug 的代码插桩.
若为非nil,则对 defun、defmacro 等定义形式的常规求值都会为 Edebug 进行插桩。
这适用于 eval-defun、eval-region 和 eval-buffer。
使用命令 M-x edebug-all-defs 可切换该选项的值。See Edebug 的代码插桩.
若为非nil,则命令 eval-defun、eval-region 和 eval-buffer
会对所有表达式插桩,即使那些不定义任何东西的表达式。
这不适用于加载或迷你缓冲区中的求值。
使用命令 M-x edebug-all-forms 可切换该选项的值。See Edebug 的代码插桩.
若为非nil,则所有宏参数都会在生成的代码中被插桩。
对任何宏而言,debug 声明都会覆盖此选项。
因此,要为部分参数求值、部分不求值的宏指定例外情况,
请使用 debug 声明指定 Edebug 表达式规范。
若为非nil,Edebug 会保存并恢复窗口配置。
这会消耗一些时间,因此如果你的程序不关心窗口配置的变化,最好将此变量设为 nil。
如果默认值导致 Edebug 在保存/恢复窗口配置时,
覆盖了你正在调试的程序所涉及缓冲区中的光标位置(例如程序会移动光标),我们也建议设为 nil。
这种情况下另一个可以尝试自定义的选项是下面的 edebug-save-displayed-buffer-points。
如果 edebug-save-windows 的值是一个列表,则只保存和恢复列表中的窗口。
你可以在 Edebug 中使用 W 命令交互式修改此变量。See Edebug 显示更新机制.
若为非nil,Edebug 会保存并恢复所有已显示缓冲区中的光标位置。
如果你正在调试的代码会修改在非选中窗口中显示的缓冲区的光标, 那么保存并恢复其他缓冲区的光标就很有必要。 如果之后 Edebug 或用户选中了该窗口,缓冲区中的光标会跳转到窗口的光标位置。
保存并恢复所有缓冲区的光标开销较大,因为需要两次选中每个窗口,因此只在需要时开启。 See Edebug 显示更新机制.
若该变量非nil,它指定 Edebug 首次激活时的初始执行模式。
可选值有:step、next、go、Go-nonstop、trace、
Trace-fast、continue、Continue-fast。
默认值为 step。
可以用 C-x C-a C-m(edebug-set-initial-mode)交互式设置该变量。
See Edebug 运行模式.
若为非nil,则跟踪每个函数的进入与退出。
跟踪输出显示在名为 *edebug-trace* 的缓冲区中,每行一个函数进入或退出记录,
按递归深度缩进。
另见 跟踪缓冲区 中的 edebug-tracing。
若为非nil,则在 Edebug 外部继续定义或执行正在运行的键盘宏。
请谨慎使用,因为该功能未经过调试测试。
See Edebug 运行模式.
若为非nil,Edebug 在显示表达式结果时会尝试移除自身添加的插桩代码。
这在调试宏时非常有用,因为宏中表达式的结果本身可能也是被插桩的表达式。
举一个人为例子:假设函数 fac 已被插桩,考虑如下形式的宏:
(defmacro test () "Edebug example."
(if (symbol-function 'fac)
...))
如果你对 test 宏插桩并单步执行,默认情况下 symbol-function 调用的结果
会包含大量 edebug-after 和 edebug-before 形式,导致难以看清实际结果。
如果 edebug-unwrap-results 为非nil,Edebug 会尝试从结果中移除这些形式。
如果你在 Edebug 激活期间修改了 edebug-on-error 或 edebug-on-quit,
它们的值要等到 下一次 通过新命令触发 Edebug 时才会生效。
若为非nil,则是一个在每个暂停点都会检测的表达式。
若结果为非nil,则中断。错误会被忽略。
See 全局中断条件.
当到达断点且执行模式为跟踪或继续时,暂停的秒数。 See Edebug 运行模式.
到达断点时是否暂停 edebug-sit-for-seconds 秒。
设为 nil 禁止暂停,非nil 允许暂停。
默认情况下,该关联列表包含一个键为 edebug 的条目,
以及由三个函数组成的列表,它们是插桩代码中调用的默认实现:
edebug-enter、edebug-before 和 edebug-after。
要全局修改 Edebug 的行为,可修改默认条目。
也可以按单个定义修改 Edebug 行为:向此 alist 添加一个自定义键和三个函数,
然后将被插桩定义的 edebug-behavior 符号属性设为新条目的键,
Edebug 就会为该定义调用新函数,而不是自身的函数。
Edebug 在包装完一个定义或闭包的代码体之后运行的函数。
在 Edebug 初始化完自身数据后,会以一个参数调用该函数:
即与该定义关联的符号,可以是实际定义的符号,也可以是 Edebug 生成的符号。
该函数可用于为每个被 Edebug 插桩的定义设置 edebug-behavior 符号属性。
要在插桩生效前检查或修改 Edebug 的插桩结果,可将此变量设为一个函数: 它接受一个参数(被插桩的顶层表达式),返回原表达式或替换后的表达式, Edebug 会将其作为最终的插桩结果使用。
Lisp 读取器会报告无效语法,但无法指出问题真正所在。 例如,在对表达式求值时出现错误 ‘解析时遇到文件结束(End of file during parsing)’, 通常表示左括号(或方括号)过多。 读取器在文件末尾检测到括号不匹配,但无法确定应该在哪里补全右括号。 同样,‘无效读取语法:")"’ 表示右括号过多或缺少左括号, 但不会指出缺失的括号位置。 那么,该如何找到需要修改的地方?
如果问题不只是括号不匹配,一种实用技巧是:
在每个 defun 开头尝试按 C-M-e(end-of-defun,see Moving by Defuns in The GNU Emacs Manual),
观察光标是否移动到该 defun 理论上应该结束的位置。
如果不是,说明该 defun 内部存在问题。
然而,括号不匹配是 Lisp 中最常见的语法错误, 我们可以针对这类情况提供更具体的建议。 (此外,在开启 Show Paren 模式的情况下, 只需将光标在代码中移动,就可能发现不匹配的括号。)
第一步是找到括号不匹配的 defun。
如果左括号过多,方法是:
跳转到文件末尾,按 C-u C-M-u(backward-up-list,see Moving by Parens in The GNU Emacs Manual)。
这会将光标移动到第一个括号不匹配的 defun 开头。
第二步是精确定位问题。
除了仔细阅读程序,没有绝对可靠的方法,
但现有的缩进通常能提示括号应该在的位置。
利用这一线索最简单的方法是:
用 C-M-q(indent-pp-sexp,see Multi-line Indent in The GNU Emacs Manual)重新缩进,观察哪些行发生了移动。
但先不要这样做! 请继续往下看
在重新缩进之前,确保该 defun 有足够的右括号。
否则,C-M-q 会报错,或者将文件剩余部分全部错误缩进。
因此,先移动到该 defun 末尾,并插入一个右括号。
不要用 C-M-e(end-of-defun)移动到那里,
因为在括号匹配之前,该命令也无法正常工作。
现在你可以回到该 defun 开头,按 C-M-q。
通常从某一位置到函数末尾的所有行会整体右移。
在该位置附近,很可能缺少一个右括号,或者多了一个左括号。
(但不要想当然;请仔细阅读代码确认。)
找到问题后,用 C-_(undo)撤销 C-M-q 的缩进,
因为原来的缩进通常更符合你期望的括号结构。
当你认为已经修复问题后,再次使用 C-M-q。 如果原来的缩进确实符合你期望的括号嵌套结构, 并且你已经补全了对应的括号,那么 C-M-q 不会做任何修改。
处理右括号过多的问题时,首先跳转到文件开头,
然后按 C-u -1 C-M-u(带参数 -1 的 backward-up-list),
找到第一个括号不匹配的 defun 的结束位置。
接着,在该 defun 开头按 C-M-f(forward-sexp,see Expressions in The GNU Emacs Manual),
找到实际匹配的右括号位置。
此时光标会停在 defun 本应结束位置之前的某处,
在该位置附近很可能存在多余的右括号。
如果在该位置未发现问题,下一步是在 defun 开头按 C-M-q(indent-pp-sexp)。
某一段代码行可能会整体左移;
若出现此情况,缺失的左括号或多余的右括号大概率出现在这些行的起始位置附近。
(但不要想当然;请仔细阅读代码确认。)
找到问题后,用 C-_(undo)撤销 C-M-q 的缩进,
因为原来的缩进通常更符合你期望的括号结构。
当你认为已经修复问题后,再次使用 C-M-q。 如果原来的缩进确实符合你期望的括号嵌套结构, 并且你已经补全了对应的括号,那么 C-M-q 不会做任何修改。
你可以对 Lisp 代码文件进行覆盖度测试:
先加载 testcover 库,
然后执行命令 M-x testcover-start RET file RET 为代码插桩。
接着调用一次或多次待测试代码。
之后执行命令 M-x testcover-mark-all,
代码会显示彩色高亮,标记出覆盖度不足的位置。
命令 M-x testcover-next-mark 会将光标向前移动到下一个高亮位置。
默认情况下:
红色高亮表示该表达式从未被完整求值;
棕色高亮表示该表达式求值结果始终相同(说明对结果的后续处理测试不足)。
但对于不可能完成求值的表达式(如 error),会跳过红色高亮;
对于预期求值结果始终相同的表达式(如 (setq x 14)),会跳过棕色高亮。
对于复杂场景,你可以在代码中添加空操作宏,为测试覆盖工具提供提示。
对 form 求值并返回其结果,同时告知覆盖度测试工具:该表达式的求值结果应始终相同。
对 form 求值,同时告知覆盖度测试工具:该表达式应永不返回。 若该表达式实际返回了值,会触发运行时错误。
Edebug 也提供覆盖度测试功能(see 覆盖度测试)。 这些功能存在部分重叠,将其整合会更合理。
如果程序运行正确但速度不够快,你希望让它运行得更快、更高效, 首先要做的就是对你的代码进行性能剖析(profile), 从而知道代码在哪些地方消耗了最多执行时间。 如果你发现某个特定函数占用了很大比例的执行时间, 就可以开始寻找优化该部分的方法。
Emacs 内置了对此的支持。
要开始剖析,输入 M-x profiler-start。
你可以选择定期采样 CPU 使用情况(cpu)、
内存分配时采样(memory),或两者同时进行。
然后运行你想要优化的代码。
之后,输入 M-x profiler-report,
为你选择剖析的每种类型(CPU 和内存)显示一个汇总缓冲区。
报告缓冲区的名称包含报告生成的时间,
因此你可以稍后生成另一份报告而不会覆盖之前的结果。
剖析完成后,输入 M-x profiler-stop
(剖析会带来少量开销,因此不建议在不实际运行待分析代码时保持开启)。
性能剖析报告缓冲区的每一行显示一个被调用的函数, 前面是自剖析开始以来该函数使用的 CPU 资源的绝对值和百分比。 如果某一行函数名左侧有 ‘+’ 符号, 你可以按 RET 展开该行,查看上层函数调用的子函数。 使用前缀参数(C-u RET)可以查看该函数下的完整调用树。 再次按 RET 会折叠回原来的状态。
按 j(profiler-report-find-entry)
或 mouse-2 跳转到光标处函数的定义。
按 d(profiler-report-describe-entry)查看函数的文档。
你可以用 C-x C-w(profiler-report-write-profile)
将剖析结果保存到文件,并用
M-x profiler-find-profile 或
M-x profiler-find-profile-other-window
读取已保存的剖析结果。
使用 =(profiler-report-compare-profile)可以对比两份剖析结果。
elp 库提供了另一种方式,
适用于你预先知道要剖析哪些 Lisp 函数的场景。
使用该库时,首先将 elp-function-list 设置为你要剖析的函数符号列表。
然后输入 M-x elp-instrument-list RET nil RET
开始对这些函数进行剖析。
运行待剖析代码后,调用 M-x elp-results 显示当前结果。
更详细的说明见文件 elp.el。
该方式仅限于剖析用 Lisp 编写的函数,不能剖析 Emacs 原语函数。
你可以使用 benchmark 库对单个 Emacs Lisp 表达式的求值耗时进行测量。
参见 benchmark.el 中的函数 benchmark-call
以及宏 benchmark-run、benchmark-run-compiled
和 benchmark-progn。
你也可以交互式使用 benchmark 命令对表达式计时。
要在 C 代码层面剖析 Emacs,可以在构建时使用
configure 的 --enable-profiling 选项。
当 Emacs 退出时,会生成文件 gmon.out,
你可以用 gprof 工具分析它。
该功能主要用于调试 Emacs 本身。
它会使上面介绍的 Lisp 层面 M-x profiler-… 命令失效。
打印(Printing)与 读取(reading) 是将 Lisp 对象与文本形式相互转换的操作。 它们使用的文本表示与读取语法已在 Lisp 数据类型 中说明。
本章介绍用于读取和打印的 Lisp 函数,同时也介绍 流(streams) —— 用于指定从哪里获取文本(读取时)或向哪里输出文本(打印时)。
读取(reading) 一个 Lisp 对象,是指将文本形式的 Lisp 表达式解析为对应的 Lisp 对象。
Lisp 程序正是通过这种方式从代码文件加载到 Lisp 环境中的。
我们把这段文本称为该对象的 读取语法(read syntax)。
例如,文本 ‘(a . 5)’ 是一个 cons 单元的读取语法,其 CAR 为 a,CDR 为数字 5。
打印(printing) 一个 Lisp 对象,是指生成表示该对象的文本—— 将对象转换为它的 打印表示(printed representation) (see 打印表示与读入语法)。 打印上面所说的 cons 单元会得到文本 ‘(a . 5)’。
读取与打印大致互为逆操作:
打印一段文本读取后得到的对象,通常会得到相同的文本;
读取一个对象打印后得到的文本,通常会得到外观相似的对象。
例如,打印符号 foo 得到文本 ‘foo’,读取该文本会返回符号 foo。
打印元素为 a 和 b 的列表得到文本 ‘(a b)’,
读取该文本会得到一个元素为 a 和 b 的列表(但不是同一个列表对象)。
不过,这两种操作并非严格互逆,主要有三类例外:
大部分用于读取文本的 Lisp 函数都会接受一个 输入流(input stream) 作为参数。 输入流指定从何处、以何种方式获取待读取的字符。 输入流可以是以下类型:
从缓冲区 buffer 中读取字符,起始位置为光标后一位。 随着字符被读取,光标会向后移动。
从标记 marker 所在的缓冲区读取字符,起始位置为标记后一位。 随着字符被读取,标记位置会向后移动。 当流是标记时,缓冲区中的光标位置不产生影响。
从字符串 string 中获取输入字符,从字符串第一个字符开始,按需读取。
输入字符由函数 function 生成,该函数必须支持两种调用方式:
t ¶t 作为流表示从迷你缓冲区读取输入。
实际上,迷你缓冲区会被激活一次,用户输入的文本会被构造成字符串并作为输入流使用。
如果 Emacs 以批处理模式运行(see Batch Mode),则使用标准输入而非迷你缓冲区。
例如:
(message "%s" (read t))
在批处理模式下会从标准输入读取一个 Lisp 表达式,并将结果打印到标准输出。
nil ¶nil 作为输入流表示使用变量 standard-input 的值;
该值是 默认输入流(default input stream),必须是一个非nil 的输入流。
符号作为输入流等价于使用该符号的函数定义(如果存在)。
下面是从缓冲区流中读取的例子,展示读取前后光标的位置:
---------- Buffer: foo ---------- This∗ is the contents of foo. ---------- Buffer: foo ----------
(read (get-buffer "foo"))
⇒ is
(read (get-buffer "foo"))
⇒ the
---------- Buffer: foo ---------- This is the∗ contents of foo. ---------- Buffer: foo ----------
注意第一次读取会跳过一个空格。读取会自动跳过有效文本前的任意空白。
下面是从标记流读取的例子,标记初始位于缓冲区开头。
读取到的值是符号 This。
---------- Buffer: foo ---------- This is the contents of foo. ---------- Buffer: foo ----------
(setq m (set-marker (make-marker) 1 (get-buffer "foo")))
⇒ #<marker at 1 in foo>
(read m)
⇒ This
m
⇒ #<marker at 5 in foo> ;; Before the first space.
下面从字符串内容中读取:
(read "(When in) the course")
⇒ (When in)
下面的例子从迷你缓冲区读取。提示语为:‘Lisp expression: ’。
(使用流 t 读取时总是使用该提示。)
提示后的内容为用户输入。
(read t)
⇒ 23
---------- Buffer: Minibuffer ----------
Lisp expression: 23 RET
---------- Buffer: Minibuffer ----------
最后是一个函数流的例子,函数名为 useless-stream。
在使用该流之前,我们先将变量 useless-list 初始化为一个字符列表。
之后每次调用 useless-stream 会从列表中取下一个字符,
或通过将字符添加到列表头部来回退字符。
(setq useless-list (append "XY()" nil))
⇒ (88 89 40 41)
(defun useless-stream (&optional unread)
(if unread
(setq useless-list (cons unread useless-list))
(prog1 (car useless-list)
(setq useless-list (cdr useless-list)))))
⇒ useless-stream
现在用构造出的流进行读取:
(read 'useless-stream)
⇒ XY
useless-list
⇒ (40 41)
注意左右括号仍然留在列表中。
Lisp 读取器遇到左括号后判定输入结束,并将其回退。
此时再次从该流读取会读到 ‘()’ 并返回 nil。
本节描述与读取操作相关的 Lisp 函数和变量。
在以下函数中,stream(stream)代表输入流(参见
上一节)。如果 stream 为 nil 或被省略,则默认使用
standard-input 的值。
若读取操作遇到未终止的列表、向量或字符串,会触发 end-of-file 错误。
该函数从 stream 读取一个文本形式的 Lisp 表达式,并将其作为 Lisp 对象返回。 这是基础的 Lisp 输入函数。
该函数从 string 中的文本读取第一个文本形式的 Lisp 表达式。 它返回一个 cons 单元,其 CAR 是该表达式,CDR 是一个整数, 表示字符串中剩余下一个字符的位置(即第一个未被读取的字符)。
若提供了 start 参数,则从字符串的索引 start 处开始读取 (第一个字符的索引为 0)。若指定了 end 参数,则读取操作会强制在该索引之前停止, 如同字符串的剩余部分不存在一样。
例如:
(read-from-string "(setq x 55) (setq y 5)")
⇒ ((setq x 55) . 11)
(read-from-string "\"A short string\"")
⇒ ("A short string" . 16)
;; Read starting at the first character.
(read-from-string "(list 112)" 0)
⇒ ((list 112) . 10)
;; Read starting at the second character.
(read-from-string "(list 112)" 1)
⇒ (list . 5)
;; Read starting at the seventh character, ;; and stopping at the ninth. (read-from-string "(list 112)" 6 8) ⇒ (11 . 8)
该函数像 read 一样从 stream 读取一个文本表达式,
但会额外将读取到的符号定位到其在 stream 中出现的位置。
出于效率考虑,仅符号 nil 不会被定位。
See 带位置信息的符号。
该函数由字节编译器(byte compiler)使用。
该变量保存默认输入流——当 stream 参数为 nil 时,
read 函数会使用此流。其默认值为 t,表示使用迷你缓冲区(minibuffer)。
若该变量值非 nil,则启用对循环结构(circular structures)
和共享结构(shared structures)的读取功能。See 循环对象的读取语法。
其默认值为 t。
在批处理模式下对 Emacs 进程的标准输入/输出流进行读写时, 有时需要确保任意二进制数据都能被原样读写,且/或不执行换行符与 CR-LF 对之间的转换。 此问题仅存在于 MS-Windows 和 MS-DOS 系统,POSIX 主机无此问题。 以下函数允许你控制 Emacs 进程任意标准流的 I/O 模式。
将 stream 切换为二进制或文本 I/O 模式。
若 mode 非 nil,则切换为二进制模式,否则切换为文本模式。
stream 的取值可以是 stdin、stdout 或 stderr。
该函数会作为副作用刷新 stream 中所有待输出的数据,
并返回 stream 之前的 I/O 模式值。
在 POSIX 主机上,该函数始终返回非 nil 值,且除了刷新待输出数据外不执行任何操作。
该谓词用于判断 object 是否具有 可读语法(readable syntax),
即能否被 Emacs Lisp 读取器(reader)写出后再读回。
若不能,该函数返回 nil;若可以,
该函数返回 object 的打印表示形式(通过 prin1 函数生成,see 输出函数)。
输出流用于指定如何处理打印产生的字符。 大多数打印函数接受一个输出流作为可选参数。 输出流的可能类型如下:
输出字符会插入到 buffer 的光标位置(point)处。 随着字符插入,光标位置会向前移动。
输出字符会插入到 marker 所指向的缓冲区中,且位于标记的位置处。 标记位置会随字符插入向前移动。 当流为标记类型时,缓冲区中的光标位置值对打印无影响, 且此类打印操作不会移动光标(除非标记指向光标位置或其之前, 此时光标会像往常一样随周围文本向前移动)。
输出字符会传递给 function,由该函数负责存储这些字符。 该函数会以单个字符为参数被调用(输出多少字符就调用多少次), 并负责将字符存储到你指定的任意位置。
t ¶输出字符会显示在回显区(echo area)中。 若 Emacs 以批处理模式运行(see Batch Mode), 则输出会写入标准输出描述符(standard output descriptor)。
nil ¶指定 nil 作为输出流表示使用 standard-output 变量的值;
该值为 默认输出流(default output stream),且不能为 nil。
作为输出流的符号等价于该符号的函数定义(若存在)。
许多有效的输出流同时也可作为输入流使用。 因此,输入流与输出流的区别更多在于如何使用 Lisp 对象,而非对象类型的不同。
以下是将缓冲区用作输出流的示例。 初始时光标位于 ‘the’ 中 ‘h’ 之前的位置。 最终光标仍位于该 ‘h’ 之前的位置。
---------- Buffer: foo ---------- This is t∗he contents of foo. ---------- Buffer: foo ----------
(print "This is the output" (get-buffer "foo"))
⇒ "This is the output"
---------- Buffer: foo ---------- This is t "This is the output" ∗he contents of foo. ---------- Buffer: foo ----------
接下来展示将标记用作输出流的用法。
初始时,标记位于缓冲区 foo 中单词 ‘the’ 的 ‘t’ 和 ‘h’ 之间。
最终,标记会越过插入的文本向前移动,使其仍位于原 ‘h’ 之前。
注意,光标位置(按常规方式显示)对此无影响。
---------- Buffer: foo ---------- This is the ∗output ---------- Buffer: foo ----------
(setq m (copy-marker 10))
⇒ #<marker at 10 in foo>
(print "More output for foo." m)
⇒ "More output for foo."
---------- Buffer: foo ---------- This is t "More output for foo." he ∗output ---------- Buffer: foo ----------
m
⇒ #<marker at 34 in foo>
以下示例展示输出到回显区的用法:
(print "Echo Area output" t)
⇒ "Echo Area output"
---------- Echo Area ----------
"Echo Area output"
---------- Echo Area ----------
最后展示将函数用作输出流的用法。
函数 eat-output 接收传入的每个字符,并将其 cons 到列表 last-output 的前端(see 构建 cons 单元与列表)。
最终,该列表包含所有输出的字符,但顺序为逆序。
(setq last-output nil)
⇒ nil
(defun eat-output (c)
(setq last-output (cons c last-output)))
⇒ eat-output
(print "This is the output" #'eat-output)
⇒ "This is the output"
last-output
⇒ (10 34 116 117 112 116 117 111 32 101 104
116 32 115 105 32 115 105 104 84 34 10)
我们可通过反转列表将输出恢复为正确顺序:
(concat (nreverse last-output))
⇒ "
\"This is the output\"
"
调用 concat 可将列表转换为字符串,便于清晰查看其内容。
该函数在调试时可用作输出流,它会将 character 写入标准错误流(standard error stream)。
例如:
(print "This is the output" #'external-debugging-output) ⊣ This is the output ⇒ "This is the output"
本节描述用于打印 Lisp 对象的 Lisp 函数 — 即将对象转换为其打印表示形式。
部分 Emacs 打印函数会在必要时为输出添加引用字符,以确保其能被正确读取。 使用的引用字符为 ‘"’ 和 ‘\’;这些字符用于区分字符串(string)与符号(symbol),并防止字符串和符号中的标点字符在读取时被当作分隔符。 See 打印表示与读入语法。 你可以通过选择不同的打印函数来指定是否添加引用字符。
如果文本需要重新读入 Lisp 中,则应使用引用字符进行打印以避免歧义。 同理,如果目的是为 Lisp 程序员清晰描述一个 Lisp 对象,也应如此。 但如果输出的目的是为了让人类阅读时更美观,通常最好不使用引用字符打印。
Lisp 对象可以引用自身。以常规方式打印自引用对象会需要无限量的文本, 且尝试这样做可能导致无限递归。Emacs 会检测此类递归,并打印 ‘#level’ 而非递归打印已在打印过程中的对象。例如,此处 ‘#0’ 表示对当前打印操作 第 0 层对象的递归引用:
(setq foo (list nil))
⇒ (nil)
(setcar foo foo)
⇒ (#0)
以下函数中,stream 代表输出流(output stream)。
(输出流的相关描述参见上一节,另可参见 See external-debugging-output,
这是一个用于调试的实用流值。)
如果 stream 为 nil 或被省略,则默认使用 standard-output 的值。
print 函数是一种便捷的打印方式。它会将 object 的打印表示形式输出到 stream,
并在 object 之前额外打印一个换行符,之后再打印一个换行符。
该函数会使用引用字符,并返回 object。例如:
(progn (print 'The\ cat\ in)
(print "the hat")
(print " came back"))
⊣
⊣ The\ cat\ in
⊣
⊣ "the hat"
⊣
⊣ " came back"
⇒ " came back"
该函数将 object 的打印表示形式输出到 stream。
它不会像 print 那样打印换行符来分隔输出,但会和 print 一样使用引用字符。
该函数返回 object。.
(progn (prin1 'The\ cat\ in)
(prin1 "the hat")
(prin1 " came back"))
⊣ The\ cat\ in"the hat"" came back"
⇒ " came back"
如果 overrides 非 nil,则其值应为 t(表示让 prin1
使用所有打印相关变量的默认值)或一个设置列表。See 覆盖输出变量。
该函数将 object 的打印表示形式输出到 stream,并返回 object。
此函数旨在生成人类可读的输出,而非供 read 函数读取的输出,
因此它不会插入引用字符,也不会在字符串内容两侧添加双引号。
多次调用该函数时,函数之间不会添加任何空格。
(progn
(princ 'The\ cat)
(princ " in the \"hat\""))
⊣ The cat in the "hat"
⇒ " in the \"hat\""
该函数向 stream 输出一个换行符。函数名是 “terminate print” 的缩写。
如果 ensure 非 nil,且 stream 已处于行首,则不会打印换行符。
请注意,此种情况下 stream 不能是函数,否则会触发错误。
如果打印了换行符,该函数返回 t。
该函数将 character 输出到 stream,并返回 character。
如果你编写了基于 Emacs 的批处理脚本并向终端发送输出,
那么每当你向 standard-output 写入换行符时,Emacs 会自动显示输出内容。
该函数允许你无需先发送换行符即可刷新 standard-output,
从而能够显示不完整的行。
该函数返回一个字符串,其中包含 prin1 函数对相同参数本应打印的文本内容。
(prin1-to-string 'foo)
⇒ "foo"
(prin1-to-string (mark-marker))
⇒ "#<marker at 2773 in strings.texi>"
如果 overrides 非nil,则其值应为t(表示让prin1使用所有打印相关变量的默认值)或一个设置列表。详情请参见 See 覆盖输出变量。
如果 noescape 非 nil,则会禁止在输出中使用引用字符。
(Emacs 19 及更高版本支持该参数。)
(prin1-to-string "foo")
⇒ "\"foo\""
(prin1-to-string "foo" t)
⇒ "foo"
如需通过其他方式获取 Lisp 对象的打印表示形式并转换为字符串,
请参见 格式化字符串 中的 format 函数。
该宏会执行 body 形式,并将 standard-output 配置为将输出写入字符串。
执行完成后,宏会返回该字符串。
例如,如果当前缓冲区(buffer)名称为 ‘foo’:
(with-output-to-string (princ "The buffer is ") (princ (buffer-name)))
上述代码会返回 "The buffer is foo"。
该函数将 object 输出到 stream,行为与 prin1 类似,
但输出格式更美观。具体来说,它会对对象进行缩进和填充,使其更易于人类阅读。
如果你需要在批处理模式下使用二进制 I/O(例如,使用本节描述的函数写入任意二进制数据, 或在非 POSIX 主机上避免换行符转换),请参见 set-binary-mode。
该变量的值为默认输出流——即当 stream 参数为 nil 时,打印函数所使用的输出流。
默认值为 t,表示在回显区(echo area)中显示。
若该变量值非 nil,则表示使用简化的读取器语法(reader syntax)打印带引号的形式,例如 (quote foo) 会打印为
'foo,而 (function foo) 会打印为 #'foo。默认值为 t。
若该变量值非 nil,则字符串中的换行符会被打印为 ‘\n’,换页符会被打印为 ‘\f’。
默认情况下,这些字符会被打印为实际的换行符和换页符。
该变量会影响带引号打印的函数 prin1 和 print,但不会影响 princ。以下是使用 prin1 的示例:
(prin1 "a\nb")
⊣ "a
⊣ b"
⇒ "a
b"
(let ((print-escape-newlines t))
(prin1 "a\nb"))
⊣ "a\nb"
⇒ "a
b"
在第二个表达式中,prin1 调用期间 print-escape-newlines 的局部绑定生效,但在打印结果时不生效。
若该变量值非 nil,则带引号打印的函数 prin1 和 print 会将字符串中的控制字符打印为反斜杠序列。
若该变量与 print-escape-newlines 均非 nil,则后者对换行符和换页符优先生效。
若该变量值非 nil,则带引号打印的函数 prin1 和 print 会将字符串中的单字节非 ASCII 字符
无条件打印为反斜杠序列。
当输出流为多字节缓冲区或指向多字节缓冲区的标记时,无论该变量取值如何,上述函数都会将单字节非 ASCII 字符 打印为反斜杠序列。
若该变量值非 nil,则带引号打印的函数 prin1 和 print 会将字符串中的多字节非 ASCII 字符
无条件打印为反斜杠序列。
当输出流为单字节缓冲区或指向单字节缓冲区的标记时,无论该变量取值如何,上述函数都会将多字节非 ASCII 字符 打印为反斜杠序列。
该变量控制打印字符串时 ‘charset‘ 文本属性的输出行为。其取值应为 nil、t 或 default。
若取值为 nil,则从不打印 charset 文本属性;若为 t,则始终打印该属性。
若取值为 default,则仅当存在 “非预期(unexpected)” 的 charset 属性时才打印该属性。对于 ASCII 字符,所有字符集均被视为
“预期的(expected)”;其他情况下,字符的预期 charset 属性由 char-charset 函数给出。
该变量的值为打印任意列表、向量或布尔向量时的最大元素数量。若待打印对象的元素数量超过该值,则会使用省略号缩写输出。
若取值为 nil(默认值),则无元素数量限制。
(setq print-length 2)
⇒ 2
(print '(1 2 3 4 5))
⊣ (1 2 ...)
⇒ (1 2 ...)
该变量的值为打印时括号和方括号的最大嵌套深度。任何嵌套深度超过该限制的列表或向量都会使用省略号缩写输出。
取值为 nil(默认值)时表示无嵌套深度限制。
这两个变量分别为 eval-expression 函数所使用的 print-length 和 print-level 值,
因此也间接作用于许多交互式求值命令(see Evaluating Emacs Lisp Expressions in The GNU Emacs Manual)。
以下变量用于检测并报告循环结构和共享结构:
默认情况下,Emacs 会将不可读对象打印为 ‘#<...>’。例如:
(prin1-to-string (make-marker))
⇒ "#<marker in no buffer>"
若该变量值非 nil,则其应为一个函数,用于处理这些不可读对象的打印逻辑。该函数会接收两个参数:待打印对象,以及
打印函数使用的 noescape 标志(see 输出函数)。
该函数的返回值可以是:nil(按默认方式打印对象)、字符串(直接打印该字符串),或其他任意对象(不打印该对象)。例如:
(let ((print-unreadable-function
(lambda (object escape) "hello")))
(prin1-to-string (make-marker)))
⇒ "hello"
若取值非 nil,则该变量启用打印时对未注册符号(see 创建与编入符号)的检测功能。启用该功能后,
未注册符号会以 ‘#:’ 为前缀打印,该前缀会告知 Lisp 读取器生成一个未注册符号。
若取值非 nil,则表示在多次打印调用间使用连续编号。这会影响 ‘#n=’ 标签和 ‘#m#’ 引用的打印编号。
请勿使用 setq 设置该变量;应仅通过 let 将其临时绑定为 t。绑定该变量时,还应将 print-number-table
绑定为 nil。
该变量持有一个向量,供打印功能内部用于实现 print-circle 特性。除非在绑定 print-continuous-numbering 时将其绑定为
nil,否则不应直接使用该变量。
该变量指定浮点数的打印格式。默认值为 nil,表示使用能无信息丢失表示该数字的最短输出形式。
若要更精确地控制输出格式,可将该变量设为一个字符串。该字符串应包含 C 函数 sprintf 所用的 ‘%’ 格式说明符。
关于格式说明符的使用限制,详见该变量的文档字符串。
当该变量值非 nil 时,代表可打印图形基础字符的整数会使用 Lisp 字符语法打印(see 基本字符语法),
其他数字则按常规方式打印。例如,列表 (4 65 -1 10) 会被打印为 ‘(4 ?A -1 ?\n)’。
更精确地说,以下值会以字符语法打印:属于 Unicode 通用类别(Letter、Number、Punctuation、Symbol、Private-use)的字符 (see Character Properties),以及拥有专属转义语法的控制字符(如换行符)。
该用户变量指定 pp 函数用于美化输出的底层函数。默认使用 pp-fill,该函数会在速度与生成自然易读且适配
fill-column 宽度的输出之间取得平衡。此前的默认值为 pp-28,该函数速度更快,但生成的输出可读性较差且不够紧凑。
上一节(see 影响输出的变量)列出了大量控制 Emacs Lisp 打印器如何格式化输出数据的变量。
这些变量通常允许用户修改,但有时你希望以默认格式输出数据,或以其他方式覆盖用户设置。
例如,当你将 Emacs Lisp 数据保存到文件中时,不希望数据被 print-length 设置截断。
因此,prin1 和 prin1-to-string 函数提供了一个可选的 overrides 参数。
该参数可以是 t(表示将所有打印变量重置为默认值),也可以是一个包含部分变量设置的列表。
列表中的每个元素可以是 t(表示 “重置为默认值(reset to defaults)”,通常作为列表的第一个元素),
或是一个点对,其 car 为代表输出变量的符号,cdr 为该变量要设置的值。
例如,以下代码仅使用默认设置进行打印:
(prin1 object nil t)
这会使用当前打印设置来打印 object,但会将 print-length 的值覆盖为 5:
(prin1 object nil '((length . 5)))
最后,这段代码仅使用默认设置打印 object,但将 print-length 绑定为 5:
(prin1 object nil '(t (length . 5)))
下面列出了可以使用的符号及其对应的变量:
length覆盖 print-length。
level覆盖 print-level。
circle覆盖 print-circle。
quoted覆盖 print-quoted。
escape-newlines覆盖 print-escape-newlines。
escape-control-characters覆盖 print-escape-control-characters。
escape-nonascii覆盖 print-escape-nonascii。
escape-multibyte覆盖 print-escape-multibyte。
charset-text-property覆盖 print-charset-text-property。
unreadeable-function覆盖 print-unreadable-function。
gensym覆盖 print-gensym。
continuous-numbering覆盖 print-continuous-numbering。
number-table覆盖 print-number-table。
float-format覆盖 float-output-format。
integers-as-characters覆盖 print-integers-as-characters。
未来可能会提供更多覆盖选项,这些选项不会直接对应到某个变量,只能通过此参数使用。
迷你缓冲区(minibuffer)是 Emacs 命令用于读取参数的特殊缓冲区,适用于比单个数值前缀参数更复杂的输入。这些参数包括文件名、缓冲区名和命令名(如 M-x)。迷你缓冲区显示在框架的最底行,与回显区位于同一位置(see The Echo Area),但仅在用于读取参数时才会出现。
在大多数方面,迷你缓冲区都是普通的 Emacs 缓冲区。大多数在缓冲区 内部 的操作(如编辑命令)在迷你缓冲区中都能正常工作。不过,许多管理缓冲区的操作并不适用于迷你缓冲区。迷你缓冲区的名称始终形如 ‘ *Minibuf-number*’,且无法修改。迷你缓冲区只显示在专门用于迷你缓冲区的特殊窗口中;这些窗口总是出现在框架底部。(有些框架没有迷你缓冲区窗口,而某些特殊框架只包含迷你缓冲区窗口;参见 Minibuffers and Frames。)
迷你缓冲区中的文本总是以 提示字符串(prompt string) 开头,该文本由使用迷你缓冲区的程序指定,用于告知用户需要输入何种内容。这段文本被标记为只读,以防意外删除或修改。它同时被标记为字段(see Defining and Using Fields),因此 beginning-of-line、forward-word、forward-sentence 和 forward-paragraph 等移动函数会在提示与实际文本的边界处停止。
迷你缓冲区的窗口通常只有一行;如果内容需要更多空间,它会自动扩展。迷你缓冲区处于激活状态时,你可以使用窗口尺寸命令临时调整其大小;退出迷你缓冲区后,窗口会恢复为默认尺寸。迷你缓冲区未激活时,你可以在框架的其他窗口中使用尺寸命令,或用鼠标拖动模式行来永久调整迷你缓冲区窗口的大小。(受当前实现细节影响,此功能要求 resize-mini-windows 为 nil。)如果框架只包含迷你缓冲区窗口,则可通过调整框架尺寸来改变其大小。
使用迷你缓冲区读取输入事件会改变 this-command 和 last-command 等变量的值(see 来自命令循环的信息)。如果你不希望这些变量被修改,应在使用迷你缓冲区的代码外围对其进行绑定。
在某些情况下,即使已有激活的迷你缓冲区,命令仍可使用新的迷你缓冲区;这样的迷你缓冲区称为 递归迷你缓冲区(recursive minibuffer)。第一个迷你缓冲区名为 ‘ *Minibuf-1*’。递归迷你缓冲区通过名称末尾数字递增来命名。(名称以空格开头,因此不会出现在普通缓冲区列表中。)在多个递归迷你缓冲区中,最内层(或最近进入的)为 激活迷你缓冲区(active minibuffer) – 可通过在其中输入 RET(exit-minibuffer)结束。我们通常直接称其为 迷你缓冲区。你可以通过设置变量 enable-recursive-minibuffers 或在命令符号上添加同名属性来允许或禁止递归迷你缓冲区(See 递归 Minibuffers)。
与其他缓冲区一样,迷你缓冲区使用局部键映射(see 按键映射)指定特殊按键绑定。调用迷你缓冲区的函数会根据任务设置其局部键映射。See 使用迷你缓冲区读取文本字符串,了解非补全类迷你缓冲区局部映射。See 执行补全的小缓冲命令,了解用于补全的迷你缓冲区局部映射。
激活的迷你缓冲区通常使用主模式 minibuffer-mode。这是 Emacs 内部模式,没有特殊功能。若要定制迷你缓冲区的设置,建议使用 minibuffer-setup-hook(see Minibuffer 杂项)而非 minibuffer-mode-hook,因为前者在迷你缓冲区完全初始化后才会运行。
迷你缓冲区未激活时,其主模式为 minibuffer-inactive-mode,键映射为 minibuffer-inactive-mode-map。这仅在迷你缓冲区位于独立框架中时真正有用。See Minibuffers and Frames。
Emacs 在批处理模式下运行时,任何从迷你缓冲区读取的请求实际上都会从启动 Emacs 时提供的标准输入描述符读取一行。该模式仅支持基础输入:迷你缓冲区的特殊功能(历史、补全等)在批处理模式下均不可用。
迷你缓冲区输入最基础的原语是 read-from-minibuffer,可用于读取字符串或文本形式的 Lisp 对象。函数 read-regexp 用于读取正则表达式(see Regular Expressions),它是一类特殊的字符串。还有用于读取命令、变量、文件名等的专用函数(see 补全)。
大多数情况下,不应在 Lisp 函数中间调用迷你缓冲区输入函数。而应在 interactive 声明中,将所有迷你缓冲区输入作为读取命令参数的一部分。See 定义命令。
该函数是从迷你缓冲区获取输入的最通用方式。默认情况下,它接受任意文本并以字符串形式返回;但如果 read 非 nil,则会使用 read 将文本转换为 Lisp 对象(see 输入函数)。
该函数首先激活迷你缓冲区,并以 prompt(必须是字符串)作为提示显示。随后用户可在迷你缓冲区中编辑文本。
当用户输入命令退出迷你缓冲区时,read-from-minibuffer 根据迷你缓冲区中的文本构造返回值。通常返回包含该文本的字符串。但如果 read 非 nil,read-from-minibuffer 会读取文本并返回未经求值的 Lisp 对象。(See 输入函数,了解读取相关信息。)
参数 default 指定可通过历史命令使用的默认值。它应为字符串、字符串列表或 nil。该字符串或多个字符串成为迷你缓冲区的 “未来历史(future history)”,用户可通过 M-n 使用。此外,如果调用提供了补全(例如通过 keymap 参数),当 default 中的值被 M-n 遍历完毕后,补全候选会被添加到“未来历史”中;参见 minibuffer-default-add-function。
如果 read 非 nil,则当用户输入为空时,default 也会用作 read 的输入。如果 default 是字符串列表,则使用第一个字符串作为输入。如果 default 为 nil,空输入会导致 end-of-file 错误。
但在通常情况下(read 为 nil),当用户输入为空时,read-from-minibuffer 会忽略 default 并返回空字符串 ""。在这一点上,它与本章中所有其他迷你缓冲区输入函数不同。
如果 keymap 非 nil,该键映射即为迷你缓冲区中使用的局部键映射。如果 keymap 省略或为 nil,则使用 minibuffer-local-map 作为键映射。指定键映射是为补全等各类应用定制迷你缓冲区的最重要方式。
参数 history 指定用于保存输入及迷你缓冲区中历史命令的历史列表变量。默认为 minibuffer-history。如果 history 为符号 t,则不记录历史。你还可以可选地指定历史列表中的起始位置。See 迷你缓冲历史。
如果变量 minibuffer-allow-text-properties 非 nil(无论是在迷你缓冲区中通过 let 绑定还是缓冲区局部绑定),则返回的字符串会保留迷你缓冲区中的所有文本属性。否则返回值会去除所有文本属性。(默认情况下该变量为 nil。)‘
minibuffer-prompt-properties 中的文本属性会应用到提示上。默认情况下,该属性列表定义了用于提示的 face。该 face(如果存在)会被添加到 face 列表末尾,并在显示前合并。
如果用户希望完全控制提示的外观,最方便的方式是在所有 face 列表末尾指定 default face。例如:
(read-from-minibuffer (concat (propertize "Bold" 'face '(bold default)) (propertize " and normal: " 'face '(default))))
如果参数 inherit-input-method 非 nil,迷你缓冲区会从进入迷你缓冲区前的当前缓冲区继承当前输入法(see Input Methods)和 enable-multibyte-characters 设置(see Text Representations)。
initial 的使用已基本不推荐;我们建议仅在为 history 指定 cons 单元时才使用非 nil 值。See 初始输入。
该函数从迷你缓冲区读取字符串并返回。参数 prompt、initial、history 和 inherit-input-method 的用法与 read-from-minibuffer 相同。使用的键映射为 minibuffer-local-map。
可选参数 default 的用法与 read-from-minibuffer 类似,区别在于:如果非 nil‘,它还指定了用户输入空内容时返回的默认值。与 read-from-minibuffer 中一样,它应为字符串、字符串列表或 nil(等价于空字符串)。当 default 为字符串时,该字符串即为默认值。当为字符串列表时,第一个字符串为默认值。(所有这些字符串都会出现在用户的 “迷你缓冲区未来历史(future minibuffer history)” 中。)
该函数通过调用 read-from-minibuffer 实现:
(read-string prompt initial history default inherit)
≡
(let ((value
(read-from-minibuffer prompt initial nil nil
history default inherit)))
(if (and (equal value "") default)
(if (consp default) (car default) default)
value))
如果你希望编辑较长的字符串(例如跨多行),使用 read-string 可能不太理想。这种情况下,跳转到新的普通缓冲区让用户编辑会更方便,可使用 read-string-from-buffer 函数实现。
该函数从迷你缓冲区以字符串形式读取正则表达式并返回。如果迷你缓冲区提示字符串 prompt 不以 ‘:’(后接可选空白)结尾,函数会在末尾添加 ‘: ’,并在前面附上默认返回值(非空时)。
可选参数 defaults 控制用户输入空内容时返回的默认值,应为以下之一:字符串;nil(等价于空字符串);字符串列表;或符号。
如果 defaults 是符号,read-regexp 会参考变量 read-regexp-defaults-function 的值(见下文),如果该值非 nil,则优先使用它而非 defaults。此时该值应为:
regexp-history-last,表示使用对应小缓冲历史列表的第一个元素(见下文)。
nil、字符串或字符串列表)将作为 defaults 的值。
read-regexp 现在会确保处理 defaults 后的结果是一个列表(即,如果值为 nil 或字符串,会将其转换为单元素列表)。在此列表基础上,read-regexp 会追加若干可能有用的输入候选,包括:
该函数最终得到一个正则表达式列表,并将其传给 read-from-minibuffer 以获取用户输入。列表的第一个元素是空输入时的默认值。列表中所有元素都会作为“未来小缓冲历史”提供给用户(see future list in The GNU Emacs Manual)。
可选参数 history 若非 nil,则是一个符号,指定要使用的小缓冲历史列表(see 迷你缓冲历史)。若省略或为 nil,历史列表默认为 regexp-history。
用户可以使用 M-s c 命令指定是否开启大小写忽略。若用户使用过该命令,返回的字符串会被设置文本属性 case-fold,取值为 fold 或 inhibit-fold。是否实际使用该值由 read-regexp 的调用者决定,为此提供了便利函数 read-regexp-case-fold-search。典型用法示例:
(let* ((regexp (read-regexp "Search for: "))
(case-fold-search (read-regexp-case-fold-search regexp)))
(re-search-forward regexp))
函数 read-regexp 可使用此变量的值来确定默认正则表达式列表。若非 nil,此变量的值应为以下之一:
regexp-history-last。
nil、字符串或字符串列表。
这些值的具体用法见上文 read-regexp。
若此变量为 nil(默认值),则 read-from-minibuffer 及所有执行迷你缓冲输入的函数在返回结果前,会移除迷你缓冲输入中的所有文本属性。
但 read-minibuffer 及相关函数(see Reading Lisp Objects With the Minibuffer)会无条件移除文本属性,不受此变量影响。
若此变量非 nil(无论是在迷你缓冲中动态绑定还是缓冲区局部绑定),则 read-from-minibuffer、read-string 及相关函数会保留文本属性。但使用补全的迷你缓冲输入函数会移除 face 属性,同时保留其他文本属性。
(minibuffer-with-setup-hook
(lambda ()
(setq-local minibuffer-allow-text-properties t))
(completing-read
"String: " (list (propertize "foobar" 'face 'baz 'data 'zot))))
=> #("foobar" 0 6 (data zot))
本例中用户输入 ‘foo’ 后按 TAB,除 face 属性外,所有文本属性均被保留。
这是 迷你缓冲读取的默认局部键映射。默认情况下,它绑定如下按键:
exit-minibuffer
exit-minibuffer
minibuffer-beginning-of-buffer
abort-recursive-edit
next-history-element
previous-history-element
next-matching-history-element
previous-matching-history-element
变量 minibuffer-mode-map 是此变量的别名。
该函数从迷你缓冲读取字符串,但不允许空白字符作为输入的一部分:空白字符会直接终止输入。参数 prompt、initial 和 inherit-input-method 的用法与 read-from-minibuffer 相同。
这是对 read-from-minibuffer 的简化接口,它会将键映射 minibuffer-local-ns-map 作为 keymap 参数传给该函数。由于键映射 minibuffer-local-ns-map 未重新绑定 C-q,因此可以通过引用方式输入空格。
该内置变量是函数 read-no-blanks-input 中使用的迷你缓冲局部键映射。除继承 minibuffer-local-map 的绑定外,默认还绑定:
根据变量 minibuffer-default-prompt-format,将提示字符串 prompt 与默认值 default 格式化。
minibuffer-default-prompt-format 是一个格式字符串(默认为 ‘" (default %s)"’),用于控制类似 ‘"Local filename (default somefile): "’ 中默认值部分的显示格式。
为允许用户自定义显示方式,需要提示输入并带有默认值的代码应使用类似如下片段:
(read-file-name (format-prompt "Local filename" file) nil file)
若 format-args 为 nil,则 prompt 作为字面字符串使用。若非 nil,则 prompt 作为格式控制串,与 format-args 一起传给 format(see 格式化字符串)。
minibuffer-default-prompt-format 可设为 ‘""’,此时不显示默认值。
若 default 为 nil,则无默认值,结果中不包含 “默认值(default value)” 字符串。若 default 为非 nil 的列表,则使用列表第一个元素作为提示中的默认值。
prompt 和 minibuffer-default-prompt-format 都会经过 substitute-command-keys 处理(see 文档中的按键绑定替换)。
若此选项非 nil(默认值),则从迷你缓冲获取输入并退出时,会恢复进入迷你缓冲所在框架的窗口配置;若与迷你缓冲窗口所属框架不同,也会恢复后者。例如,用户在同一框架使用迷你缓冲时拆分窗口,退出迷你缓冲后该拆分会被撤销。
若此选项为 nil,则不进行恢复,上述窗口拆分在退出迷你缓冲后会保留。
本节描述用于通过迷你缓冲读取 Lisp 对象的函数。
该函数使用迷你缓冲读取一个 Lisp 对象,不进行求值直接返回。参数 prompt 和 initial 的用法与 read-from-minibuffer 相同。
这是对 read-from-minibuffer 的简化接口:
(read-minibuffer prompt initial) ≡ (let (minibuffer-allow-text-properties) (read-from-minibuffer prompt initial nil t))
下面示例中,我们提供字符串 "(testing)" 作为初始输入:
(read-minibuffer
"Enter an expression: " (format "%s" '(testing)))
;; Here is how the minibuffer is displayed:
---------- Buffer: Minibuffer ---------- Enter an expression: (testing)∗ ---------- Buffer: Minibuffer ----------
用户可直接按 RET 使用初始输入作为默认值,也可编辑后再输入。
该函数使用迷你缓冲读取一个 Lisp 表达式,对其求值并返回结果。参数 prompt 和 initial 的用法与 read-from-minibuffer 相同。
该函数仅对 read-minibuffer 的调用结果进行求值:
(eval-minibuffer prompt initial) ≡ (eval (read-minibuffer prompt initial))
该函数在迷你缓冲中读取 Lisp 表达式,求值并返回结果。它与 eval-minibuffer 的区别在于:初始 form 不是可选参数,且被当作 Lisp 对象转换为打印表示,而非文本字符串。它使用 prin1 打印,因此如果是字符串,初始文本中会出现双引号(‘"’)。See 输出函数。
下面示例中,我们向用户提供一个初始内容已是合法表达式的输入:
(edit-and-eval-command "Please edit: " '(forward-word 1)) ;; After evaluation of the preceding expression, ;; the following appears in the minibuffer:
---------- Buffer: Minibuffer ---------- Please edit: (forward-word 1)∗ ---------- Buffer: Minibuffer ----------
直接按 RET 会退出小缓冲并求值该表达式,从而将光标向前移动一个单词。
迷你缓冲历史列表(minibuffer history list) 用于记录之前的迷你缓冲输入,方便用户重复使用。它是一个变量,值为字符串列表(之前的输入),最近输入排在最前。
Emacs 提供多个独立的迷你缓冲历史列表,用于不同类型的输入。Lisp 程序员需要为每次迷你缓冲使用指定正确的历史列表。
可以通过 read-from-minibuffer 或 completing-read 的可选参数 history 指定低迷缓冲历史列表,可选值如下:
使用变量 variable(符号)作为历史列表。
使用变量 variable(符号)作为历史列表,并指定初始历史位置为 startpos(非负整数)。
startpos 为 0 等价于只指定符号 variable。previous-history-element 会在小缓冲中显示历史列表最近的元素。若指定正整数 startpos,小缓冲历史函数的行为如同当前小缓冲显示的是历史元素 (elt variable (1- startpos))。
为保持一致,应同时通过小缓冲输入函数的 initial 参数,将该历史元素设为小缓冲初始内容(see 初始输入)。
若不指定 history,则使用默认历史列表 minibuffer-history。其他标准历史列表见下文。你也可以创建自定义历史列表变量,只需在首次使用前将其初始化为 nil。若该变量是缓冲区局部变量,则每个缓冲区拥有独立的输入历史列表。
read-from-minibuffer 和 completing-read 都会自动向历史列表添加新元素,并提供命令让用户重复使用列表中的条目(see Minibuffer 命令)。程序使用历史列表只需完成初始化,并在需要时将其名称传给输入函数即可。在小缓冲输入函数未使用时,手动修改历史列表也是安全的。
默认情况下,当 M-n(next-history-element,see next-history-element)到达发起小缓冲输入的命令所提供的默认值列表末尾时,M-n 会将 minibuffer-completion-table 指定的所有补全候选(see 执行补全的小缓冲命令)添加到默认值列表,使这些候选作为 “未来历史(future history)” 可用。程序可通过变量 minibuffer-default-add-function 控制这一行为:若其值不是函数,则禁用自动添加;也可将该变量设为自定义函数,只添加部分候选或其他值到 “未来历史(future history)”。
向历史列表添加新元素的 Emacs 函数会在列表过长时删除旧元素。变量 history-length 指定大多数历史列表的最大长度。若要为特定历史列表指定不同最大长度,可将长度存入该历史列表符号的 history-length 属性中。变量 history-delete-duplicates 指定是否删除历史中的重复项。
若新元素 newelt 非空字符串,此函数将其添加到变量 history-var 存储的历史列表,并返回更新后的历史列表。列表长度会被限制为 maxelt(若非 nil)或 history-length(见下文)。maxelt 的取值含义与 history-length 相同。
history-var 不能指向词法变量。
通常,若 history-delete-duplicates 非 nil,add-to-history 会删除历史列表中的重复成员。但若 keep-all 非 nil,则不删除重复项,即使 newelt 为空也会添加到列表。
若此变量值为 nil,从小缓冲读取的标准函数不会向历史列表添加新元素。这允许 Lisp 程序通过 add-to-history 显式管理输入历史。默认值为 t。
此变量的值指定所有未自行设置最大长度的历史列表的最大长度。若值为 t,表示无长度限制(不删除旧元素)。若某历史列表变量的符号拥有非 nil 的 history-length 属性,则该属性会覆盖此变量对该历史列表的作用。
若此变量值为 t,则添加新历史元素时,会删除所有之前相同的元素。
以下是部分标准小缓冲历史列表变量:
小缓冲历史输入的默认历史列表。
query-replace 参数(及其他命令类似参数)的历史列表。
文件名参数的历史列表。
缓冲区名参数的历史列表。
正则表达式参数的历史列表。
扩展命令名参数的历史列表。
Shell 命令参数的历史列表。
待求值 Lisp 表达式参数的历史列表。
面孔参数的历史列表。
read-variable 读取的变量名参数的历史列表。
read-number 读取的数字的历史列表。
goto-line 参数的历史列表。通过自定义用户选项 goto-line-history-local,可使该变量在每个缓冲区中局部化。
多个小缓冲输入函数都有一个名为 initial 的参数。这是一个基本已不推荐使用的特性,用于指定小缓冲启动时带有预设文本,而非通常的空内容。
若 initial 是字符串,用户开始编辑文本时,小缓冲初始包含该字符串内容,光标位于末尾。如果用户直接按 RET 退出小缓冲,将使用初始输入字符串作为返回值。
我们不建议为 initial 使用非 nil 的值,因为初始输入是一种侵入式接口。历史列表和默认值为用户提供有用默认输入的方式更加便捷。
只有一种情况应当为 initial 参数指定字符串:即为 history 参数指定了一个 cons 单元时。See 迷你缓冲历史。
initial 也可以是格式为 (string . position) 的 cons 单元。这表示在小缓冲中插入 string,但将光标置于字符串内的 position 位置。
由于历史原因,position 在不同函数中的实现不一致。在 completing-read 中,position 从 0 开始计数:0 表示字符串开头,1 表示第一个字符之后,依此类推。在 read-minibuffer 以及其他支持该参数的非补全小缓冲输入函数中,1 表示字符串开头,2 表示第一个字符之后,依此类推。
将 cons 单元用作 initial 参数的值已不推荐使用。
补全(Completion)是一项根据名称缩写自动填充剩余部分的功能。补全通过将用户输入与合法名称列表对比,确定用户已输入内容能唯一确定名称的多少部分来工作。例如,当你输入 C-x b(switch-to-buffer),然后
输入目标缓冲区名称的前几个字母,再按 TAB(minibuffer-complete),Emacs 会尽可能补全名称。
Emacs 标准命令为符号、文件、缓冲区、进程等名称提供补全;使用本节中的函数,你可以为其他类型名称实现补全功能。
函数 try-completion 是补全的基础原语:它根据给定的初始字符串和匹配字符串集合,返回最长可确定的补全结果。
函数 completing-read 提供更高级的补全接口。调用 completing-read 时指定如何确定合法名称列表,该函数会激活小缓冲并使用局部键映射,将若干按键绑定到补全相关命令。其他函数为读取特定类型名称并使用补全提供便捷简化接口。
下列补全函数本身与小缓冲无关。在此介绍是为了与使用小缓冲的高级补全功能放在一起。
该函数返回 collection 中所有可补全项与 string 的最长公共前缀子串。
collection 称为 补全表(completion table)。其值必须是字符串或 cons 单元列表、obarray、哈希表或补全函数。
try-completion 将 string 与补全表指定的所有合法补全项对比。若无匹配项,返回 nil。若仅有一个精确匹配项,返回 t。否则返回所有可能匹配项的最长公共初始序列。
若 collection 是列表,合法补全项由列表元素指定:每个元素应为字符串,或 CAR 为字符串或符号的 cons 单元(符号通过 symbol-name 转为字符串)。列表中其他类型元素会被忽略。
若 collection 是 obarray(see 创建与编入符号),则 obarray 中所有符号的名称构成合法补全集合。
若 collection 是哈希表,则字符串或符号类型的键为可补全项,其他键被忽略。
也可使用函数作为 collection。此时补全完全由该函数负责;try-completion 直接返回该函数的结果。函数被调用时传入三个参数:string、predicate 和 nil(第三个参数使同一函数可同时用于 all-completions 并区分行为)。See 可编程补全。
若参数 predicate 非 nil,则必须是单参数函数(若 collection 是哈希表,则为双参数函数)。它用于测试每个可能匹配,仅当 predicate 返回非 nil 时匹配有效。传给 predicate 的参数可以是 alist 中的字符串或 cons 单元(其 CAR 为字符串),或 obarray 中的符号( 不是 符号名)。若 collection 是哈希表,predicate 接收两个参数:字符串键与对应值。
此外,可接受的补全项还必须匹配 completion-regexp-list 中的所有正则表达式(除非 collection 是函数,此时需由该函数自行处理 completion-regexp-list)。
下面第一个例子中,字符串 ‘foo’ 与 alist 中的三个 CAR 匹配。所有匹配均以 ‘fooba’ 开头,因此结果为该字符串。第二个例子中仅有一个精确匹配,返回值为 t。
(try-completion
"foo"
'(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4)))
⇒ "fooba"
(try-completion "foo" '(("barfoo" 2) ("foo" 3)))
⇒ t
下例中,许多符号以 ‘forw’ 开头,且全部以 ‘forward’ 开头。多数符号后接 ‘-’,但并非全部,因此最多只能补全到 ‘forward’。
(try-completion "forw" obarray)
⇒ "forward"
最后一例中,三个可能匹配里只有两个通过谓词 test(字符串 ‘foobaz’ 太短)。两者均以 ‘foobar’ 开头。
(defun test (s)
(> (length (car s)) 6))
⇒ test
(try-completion
"foo"
'(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
'test)
⇒ "foobar"
该函数返回 string 的所有可能补全项组成的列表。参数
与 try-completion 相同,且以相同方式使用 completion-regexp-list。
若 collection 是函数,会以三个参数调用:string、predicate 和 t;然后 all-completions 返回该函数的结果。See 可编程补全。
以下示例使用 try-completion 示例中的函数 test:
(defun test (s)
(> (length (car s)) 6))
⇒ test
(all-completions
"foo"
'(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
'test)
⇒ ("foobar1" "foobar2")
若 string 是 collection 和 predicate 指定的合法补全选项,该函数返回非 nil。参数与 try-completion 相同。例如,若 collection 是字符串列表,则当 string 出现在列表中且满足 predicate 时返回真。
该函数以与 try-completion 相同的方式使用 completion-regexp-list。
若 predicate 非 nil,且 collection 包含多个由 compare-strings(按 completion-ignore-case)判定为相等的字符串,则 predicate 应要么全部接受要么全部拒绝。否则 test-completion 的返回值本质上不可预测。
若 collection 是函数,会以三个参数调用:string、predicate 和 lambda;test-completion 直接返回该函数结果。
该函数假设 string 保存光标前文本、suffix 保存光标后文本,返回 collection 操作字段的边界。
通常补全作用于整个字符串,因此对所有常规集合,它始终返回 (0 . (length suffix))。但更复杂的补全(如文件补全)会逐字段处理。例如,"/usr/sh" 的补全会包含 "/usr/share/",但不包含 "/usr/share/doc"(即使存在)。同样,对 "/usr/sh" 的 all-completions 不会返回 "/usr/share/",只返回 "share/"。因此若 string 为 "/usr/sh"、suffix 为 "e/doc",completion-boundaries 会返回 (5 . 1),表示集合只返回 "/usr/" 之后、"/doc" 之前区域的补全信息。try-completion 不受非平凡边界影响;例如对 "/usr/sh" 仍可能返回 "/usr/share/" 而非 "share/"。
若将补全 alist 存入变量,应通过为其设置非 nil 的 risky-local-variable 属性将变量标记为风险变量。See 文件局部变量。
若此变量值非 nil,补全时不区分大小写。在 read-file-name 中,该变量会被 read-file-name-completion-ignore-case 覆盖(see 读取文件名);在 read-buffer 中,会被 read-buffer-completion-ignore-case 覆盖(see 高级补全函数)。
这是一个正则表达式列表。补全函数仅接受匹配列表中所有正则表达式的补全项,匹配时 case-fold-search(see Searching and Case)绑定为 completion-ignore-case 的值。
不要全局将此变量设为非 nil,这不安全且可能导致补全命令出错。此变量只应在调用基础补全函数(try-completion、test-completion、all-completions)时局部绑定为非 nil。
该宏以惰性方式将变量 var 初始化为补全集合,直到首次使用时才计算实际内容。使用此宏生成一个值并存入 var。首次使用 var 执行补全时,通过无参数调用 fun 完成实际计算,fun 返回的值成为 var 的永久值。
示例:
(defvar foo (lazy-completion-table foo make-my-alist))
存在多个接收现有补全表并返回修改版本的函数。completion-table-case-fold 返回不区分大小写的表。completion-table-in-turn 和 completion-table-merge 以不同方式合并多个输入表。completion-table-subvert 修改表以使用不同初始前缀。completion-table-with-quoting 返回适合处理带引号文本的表。completion-table-with-predicate 使用谓词函数过滤表。completion-table-with-terminator 添加终止字符串。
本节描述用于带补全功能从小缓冲读取输入的基础接口。
该函数在小缓冲中读取字符串,并通过提供补全辅助用户输入。它使用提示字符串 prompt(必须为字符串)激活小缓冲。
实际补全通过将补全表 collection 和补全谓词 predicate 传给函数 try-completion 完成(see 基础补全函数)。这一过程在补全所使用的局部键映射中绑定的特定命令里执行。其中部分命令也会调用 test-completion。因此,若 predicate 非 nil,它必须与 collection 及 completion-ignore-case 兼容。See Definition of test-completion。
关于 collection 为函数时的详细要求,参见 see 可编程补全。
可选参数 require-match 的值决定用户如何退出小缓冲:
nil,常规小缓冲退出命令无论小缓冲中输入内容如何均可生效。
t,常规小缓冲退出命令仅在输入可补全为 collection 中元素时才允许退出。
confirm,用户可使用任意输入退出,但如果输入不是 collection 中的元素,则会要求确认。
confirm-after-completion,用户可使用任意输入退出,但如果前一条命令是补全命令(即 minibuffer-confirm-exit-commands 中的命令之一)且结果输入不是 collection 中的元素,则会要求确认。See 执行补全的小缓冲命令。
nil。
t 处理,区别在于如果执行了补全操作,退出命令不会直接退出。
但无论 require-match 取值如何,空输入始终允许;此时若 default 为列表,completing-read 返回 default 的第一个元素;若 default 为 nil,返回 "";否则返回 default。default 中的字符串也可通过历史命令供用户使用(see Minibuffer 命令)。此外,当用户通过 M-n 遍历完 default 中的值后,补全候选会被添加到 “未来历史(future history)” 中;参见 minibuffer-default-add-function。
若 require-match 为 nil,函数 completing-read 使用 minibuffer-local-completion-map 作为键映射;若非 nil,则使用 minibuffer-local-must-match-map。See 执行补全的小缓冲命令。
参数 history 指定用于保存输入和小缓冲历史命令的历史列表变量,默认为 minibuffer-history。若 history 为符号 t,则不记录历史。See 迷你缓冲历史。
参数 initial 基本已不推荐使用;我们建议仅在为 history 指定 cons 单元时才使用非 nil 值。See 初始输入。默认输入请使用 default。
若参数 inherit-input-method 非 nil,则小缓冲从进入小缓冲前的当前缓冲区继承当前输入法(see Input Methods)和 enable-multibyte-characters 设置(see Text Representations)。
若变量 completion-ignore-case 非 nil,补全时将输入与可能匹配项对比不区分大小写。See 基础补全函数。在此模式下,predicate 也必须不区分大小写,否则会出现意外结果。
使用 completing-read 的示例:
(completing-read
"Complete a foo: "
'(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
nil t "fo")
;; After evaluation of the preceding expression, ;; the following appears in the minibuffer: ---------- Buffer: Minibuffer ---------- Complete a foo: fo∗ ---------- Buffer: Minibuffer ----------
若用户随后输入 DEL DEL b RET,completing-read 返回 barfoo。
completing-read 会绑定若干变量,用于向实际执行补全的命令传递信息。这些变量将在下一节描述。
此变量的值必须是一个函数,由 completing-read 调用以实际执行工作。它应接收与 completing-read 相同的参数。可将其绑定到其他函数,以完全覆盖 completing-read 的常规行为。
若需要提示用户输入多个字符串,例如列表的多个元素或连接的多个参数(如用户、主机、端口),可使用 completing-read-multiple。它允许输入由分隔符字符串分隔的多个字符串(默认为制表符和逗号;可自定义 crm-separator 修改),并为用户输入的每个单独字符串提供补全。返回读取到的字符串列表。
本节描述在小缓冲中执行补全所使用的键映射、命令和用户选项。
此变量的值是小缓冲中用于补全的补全表(see 基础补全函数)。这是一个缓冲区局部变量,保存 completing-read 传递给 try-completion 的内容。由 minibuffer-complete 等小缓冲补全命令使用。
此变量的值是 completing-read 传递给 try-completion 的谓词。该变量也被其他小缓冲补全函数使用。
此变量决定 Emacs 在退出小缓冲前是否要求确认;completing-read 设置此变量,函数 minibuffer-complete-and-exit 在退出前检查其值。若值为 nil,无需确认。若值为 confirm,用户可使用非有效补全的输入退出,但 Emacs 会要求确认。若值为 confirm-after-completion,用户可使用非有效补全的输入退出,但如果用户在执行 minibuffer-confirm-exit-commands 中的任意补全命令后立即提交输入,Emacs 会要求确认。
此变量保存一个命令列表。当 completing-read 的 require-match 参数为 confirm-after-completion 时,如果用户在调用此列表中的任意命令后立即尝试退出小缓冲,Emacs 会要求确认。
此函数至多以单个单词为单位补全小缓冲内容。即使小缓冲内容只有唯一补全项,minibuffer-complete-word 也不会补全超出第一个非单词构成字符的内容。See Syntax Tables。
此函数尽可能补全小缓冲内容。
此函数补全小缓冲内容,若无需确认(即 minibuffer-completion-confirm 为 nil)则退出。若 需要 确认,可通过立即重复执行此命令完成确认 — 该命令被设计为连续执行两次时无需确认。
此函数生成当前小缓冲内容的所有可能补全项列表。它通过调用 all-completions 实现,使用变量 minibuffer-completion-table 的值作为 collection 参数,使用变量 minibuffer-completion-predicate 的值作为 predicate 参数。补全列表会在名为 *Completions* 的缓冲区中显示。
此函数将 completions 显示到 standard-output 流,通常是一个缓冲区。(有关流的更多信息,参见 see Lisp 对象的读取与打印。)参数 completions 通常是刚由 all-completions 返回的补全列表,但并非必须如此。每个元素可以是符号或字符串,直接打印即可。也可以是包含两个字符串的列表,打印效果如同字符串拼接。两个字符串中,第一个是实际补全内容,第二个作为注释。
此函数由 minibuffer-completion-help 调用。常见用法是与 with-output-to-temp-buffer 配合使用,示例:
(with-output-to-temp-buffer "*Completions*"
(display-completion-list
(all-completions (buffer-string) my-alist)))
若此变量非 nil,当无法继续补全(下一个字符无法唯一确定)时,补全命令会自动显示可能的补全项列表。
当不要求必须精确匹配某个补全项时,completing-read 使用此值作为局部键映射。默认情况下,该键映射绑定如下:
minibuffer-completion-help
minibuffer-complete-word
minibuffer-complete
并以 minibuffer-local-map 作为父键映射(see Definition of minibuffer-local-map)。
当要求必须精确匹配某个补全项时,completing-read 使用此值作为局部键映射。因此,没有按键绑定到无条件退出小缓冲的命令 exit-minibuffer。默认情况下,该键映射绑定如下:
minibuffer-complete-and-exit
minibuffer-complete-and-exit
并以 minibuffer-local-completion-map 作为父键映射。
这是一个精简键映射,仅取消绑定 SPC;因为文件名可以包含空格。函数 read-file-name 将此键映射与 minibuffer-local-completion-map 或 minibuffer-local-must-match-map 结合使用。
若非 nil,命令 M-< 在光标位于提示结尾之后时会跳转到提示结尾;若光标位于提示结尾处或之前,则跳转到缓冲区开头。若此变量为 nil,该命令行为与 beginning-of-buffer 一致。
本节描述用于通过补全读取特定类型名称的更高级、更便捷的函数。
大多数情况下,你不应在 Lisp 函数的中间调用这些函数。尽可能将所有小缓冲区输入
作为读取命令参数的一部分,放在 interactive 声明中完成。See 定义命令。
该函数读取一个缓冲区的名称并以字符串形式返回。
它使用 prompt 作为提示信息。参数 default 是默认名称,
即当用户以空小缓冲区退出时返回的值。如果非 nil,它可以是字符串、
字符串列表或缓冲区对象。如果是列表,则默认值为列表的第一个元素。
该值会显示在提示中,但不会作为初始内容插入小缓冲区。
参数 prompt 应当是以冒号和空格结尾的字符串。
如果 default 非 nil,函数会将其插入到 prompt 的冒号之前,
以遵循带默认值的小缓冲区读取约定(see Emacs Programming Tips)。
可选参数 require-match 的含义与 completing-read 中相同。
See 补全与小缓冲。
可选参数 predicate 若非 nil,指定一个用于过滤待考虑缓冲区的函数:
该函数会以每个候选缓冲区为参数被调用,返回 nil 表示拒绝该候选,
返回非 nil 表示接受。
在下例中,用户输入 ‘minibuffer.t’,然后按下 RET。
参数 require-match 为 t,且唯一以该输入开头的缓冲区名为
‘minibuffer.texi’,因此返回该名称。
(read-buffer "Buffer name: " "foo" t)
;; After evaluation of the preceding expression, ;; the following prompt appears, ;; with an empty minibuffer:
---------- Buffer: Minibuffer ---------- Buffer name (default foo): ∗ ---------- Buffer: Minibuffer ----------
;; The user types minibuffer.t RET.
⇒ "minibuffer.texi"
如果该变量非 nil,则指定一个用于读取缓冲区名称的函数。
read-buffer 会调用该函数而非执行自身的常规逻辑,
并将传入 read-buffer 的相同参数传递给它。
如果该变量非 nil,read-buffer 在读取缓冲区名称并执行补全时忽略大小写。
该函数读取一个命令的名称并以 Lisp 符号形式返回。
参数 prompt 的用法与 read-from-minibuffer 中相同。
回忆一下:命令是指 commandp 返回 t 的任何对象,
命令名是指 commandp 返回 t 的符号。See 交互式调用。
参数 default 指定用户输入空内容时返回的值。
它可以是符号、字符串或字符串列表。
如果是字符串,read-command 会在返回前将其 intern。
如果是列表,read-command 会将列表第一个元素 intern。
如果 default 为 nil,表示未指定默认值;
此时若用户输入空内容,返回值为 (intern ""),
即一个名称为空字符串的符号,其打印形式为 ##(see 符号类型)。
(read-command "Command name? ")
;; After evaluation of the preceding expression, ;; the following prompt appears with an empty minibuffer:
---------- Buffer: Minibuffer ---------- Command name? ---------- Buffer: Minibuffer ----------
如果用户输入 forward-c RET,该函数返回 forward-char。
read-command 是 completing-read 的简化接口。
它使用变量 obarray 在当前所有 Lisp 符号中进行补全,
并使用 commandp 作为谓词,只接受命令名:
(read-command prompt)
≡
(intern (completing-read prompt obarray
'commandp t nil))
该函数读取一个可自定义变量的名称并以符号形式返回。
其参数形式与 read-command 相同。
行为也与 read-command 类似,区别仅在于它使用谓词
custom-variable-p 而非 commandp。
该函数读取一个表示颜色规格的字符串,可以是颜色名或类似 #RRRGGGBBB 的 RGB 十六进制值。
它以 prompt 作为提示(默认:"Color (name or #RGB triplet):"),
并为颜色名提供补全,但不为 RGB 十六进制值提供补全。
除标准颜色名外,补全候选还包括光标处的前景色和背景色。
合法的 RGB 值格式见 Color Names。
函数返回值是用户在小缓冲区中输入的字符串。
但是,当交互式调用或可选参数 convert 非 nil 时,
它会将输入的颜色名转换为对应的 RGB 值字符串并返回该值。
该函数要求输入合法的颜色规格。
当 allow-empty 非 nil 且用户输入空内容时,允许空颜色名。
交互式调用或 display 非 nil 时,返回值也会在回显区显示。
可选参数 foreground 和 face 控制 *Completions* 缓冲区中
补全候选的显示外观。候选以指定的 face 显示,但颜色不同:
如果 foreground 非 nil,前景色设为候选对应的颜色,
否则将背景色设为候选对应的颜色。
另请参见 User-Chosen Coding Systems 中的 read-coding-system
和 read-non-nil-coding-system,以及 Input Methods 中的
read-input-method-name。
高级补全函数 read-file-name、read-directory-name
和 read-shell-command 分别用于读取文件名、目录名和 Shell 命令。
它们提供了专门的功能,包括自动插入默认目录。
该函数读取一个文件名,使用 prompt 作为提示并提供补全。
作为一种例外情况,如果以下所有条件均成立, 该函数将使用图形文件对话框而非小缓冲区读取文件名:
use-dialog-box 非 nil。
See Dialog Boxes in The GNU Emacs Manual。
使用图形文件对话框时的确切行为与平台相关。 这里我们只说明使用小缓冲区时的行为。
read-file-name 不会自动展开返回的文件名。
如果需要绝对文件名,你可以自行调用 expand-file-name。
可选参数 require-match 的含义与 completing-read 中相同。
See 补全与小缓冲。
参数 directory 指定用于补全相对文件名的目录。
它应当是一个绝对目录名。
如果变量 insert-default-directory 非 nil,
directory 也会作为初始内容插入到小缓冲区中。
它的默认值为当前缓冲区的 default-directory。
如果你指定了 initial,它是要插入到缓冲区中的初始文件名
(如果插入了 directory,则在其后面)。
在这种情况下,光标位于 initial 的开头。
initial 的默认值为 nil——不插入任何文件名。
要了解 initial 的作用,可以在访问文件的缓冲区中试用命令
C-x C-v。请注意:在大多数情况下,我们建议使用 default
而非 initial。
如果 default 非 nil,那么当用户以
read-file-name 最初插入的非空内容退出小缓冲区时,
函数将返回 default。
如果 insert-default-directory 非 nil(默认如此),
小缓冲区的初始内容始终非空。
无论 require-match 的值如何,都不会检查 default 的有效性。
但是,如果 require-match 非 nil,
小缓冲区的初始内容应当是一个合法的文件(或目录)名。
否则,如果用户未做任何编辑就退出,read-file-name 会尝试补全,
并且不会返回 default。
default 也可以通过历史命令访问。
如果 default 为 nil,read-file-name
会尝试寻找一个替代默认值,其处理方式与显式指定完全相同。
如果 default 为 nil 但 initial 非 nil,
则默认值为由 directory 和 initial 得到的绝对文件名。
如果 default 和 initial 均为 nil
且缓冲区正在访问某个文件,read-file-name
会使用该文件的绝对文件名作为默认值。
如果缓冲区未访问任何文件,则没有默认值。
在这种情况下,如果用户不做任何编辑直接按 RET,
read-file-name 只返回小缓冲区预先插入的内容。
如果用户在空的小缓冲区中按 RET, 无论 require-match 的值如何,该函数都返回空字符串。 例如,用户可以通过 M-x set-visited-file-name 使当前缓冲区不访问任何文件。
如果 predicate 非 nil,它指定一个单参数函数,
用于判断哪些文件名是可接受的补全候选项。
如果 predicate 对某个文件名返回非 nil,
则该文件名是可接受的值。
下面是使用 read-file-name 的示例:如果用户在空的小缓冲区中按 RET,
无论 require-match 的值如何,该函数都返回空字符串。
例如,用户可以通过 M-x set-visited-file-name
使当前缓冲区不访问任何文件。
如果 predicate 非 nil,它指定一个单参数函数,
用于判断哪些文件名是可接受的补全候选项。
如果 predicate 对某个文件名返回非 nil,
则该文件名是可接受的值。
下面是使用 read-file-name 的示例:
(read-file-name "The file is ") ;; After evaluation of the preceding expression, ;; the following appears in the minibuffer:
---------- Buffer: Minibuffer ---------- The file is /gp/gnu/elisp/∗ ---------- Buffer: Minibuffer ----------
输入 manual TAB 会得到如下结果:
---------- Buffer: Minibuffer ---------- The file is /gp/gnu/elisp/manual.texi∗ ---------- Buffer: Minibuffer ----------
如果用户按 RET,read-file-name
会将文件名以字符串 "/gp/gnu/elisp/manual.texi" 形式返回。
如果非 nil,它应当是一个与 read-file-name
接受相同参数的函数。当调用 read-file-name 时,
它会使用传入的参数调用该函数,而不执行自身的常规逻辑。
如果该变量非 nil,read-file-name 在执行补全时忽略大小写。
该函数与 read-file-name 类似,但只允许将目录名作为补全候选项。
如果 default 为 nil 且 initial 非 nil,
read-directory-name 会通过组合 directory
(如果 directory 为 nil,则使用当前缓冲区的默认目录)
和 initial 构造一个替代默认值。
如果 default 和 initial 均为 nil,
该函数使用 directory 作为替代默认值,
如果 directory 为 nil,则使用当前缓冲区的默认目录。
该变量由 read-file-name 使用,
因此也间接地被大多数读取文件名的命令使用。
(这包括所有在交互式形式中使用代码字符 ‘f’ 或 ‘F’ 的命令。
See Code Characters for interactive。)
它的值控制 read-file-name 是否在开始时
将默认目录名(以及可能的初始文件名)放入小缓冲区。
如果该变量的值为 nil,
则 read-file-name 不会在小缓冲区中放入任何初始输入
(除非你通过 initial 参数指定初始输入)。
在这种情况下,默认目录仍会用于相对文件名的补全,但不会显示出来。
如果该变量为 nil 且小缓冲区初始内容为空,
用户可能需要显式获取下一个历史元素才能访问默认值。
如果该变量非 nil,小缓冲区初始内容始终非空,
用户只需在未编辑的小缓冲区中直接按 RET
即可获取默认值。(见上文。)
例如:
;; Here the minibuffer starts out with the default directory.
(let ((insert-default-directory t))
(read-file-name "The file is "))
---------- Buffer: Minibuffer ---------- The file is ~lewis/manual/∗ ---------- Buffer: Minibuffer ----------
;; Here the minibuffer is empty and only the prompt ;; appears on its line. (let ((insert-default-directory nil)) (read-file-name "The file is "))
---------- Buffer: Minibuffer ---------- The file is ∗ ---------- Buffer: Minibuffer ----------
该函数从小缓冲区读取一条 Shell 命令, 使用 prompt 作为提示并提供智能补全。 它会对命令的第一个单词使用适合命令名的候选项进行补全, 对命令的其余单词则按照文件名进行补全。
该函数使用 minibuffer-local-shell-command-map
作为小缓冲区输入的键盘映射。
参数 history 指定要使用的历史列表;
如果省略或为 nil,则默认为 shell-command-history
(see shell-command-history)。
可选参数 initial 指定小缓冲区的初始内容
(see 初始输入)。
如果存在,args 的其余部分将作为
read-from-minibuffer 中的 default
和 inherit-input-method 参数使用
(see 使用迷你缓冲区读取文本字符串)。
该键盘映射由 read-shell-command 使用,
用于补全作为 Shell 命令一部分的命令名和文件名。
它以 minibuffer-local-map 作为父键盘映射,
并将 TAB 绑定到 completion-at-point。
下面是一些可用于改变默认补全行为的变量。
该变量的值是一个补全风格(符号)列表,用于执行补全操作。
补全风格(completion style)是一组用于生成补全项的规则。
列表中的每个符号都必须在 completion-styles-alist 中有对应的条目。
该变量存储可用的补全风格列表。 列表中的每个元素具有以下形式:
(style try-completion all-completions doc)
其中,style 是补全风格的名称(一个符号),
可在 completion-styles 变量中使用以指代该风格;
try-completion 是执行补全的函数;
all-completions 是列出补全项的函数;
doc 是描述该补全风格的字符串。
try-completion 和 all-completions 函数
均应接受四个参数:string、collection、
predicate 和 point。
参数 string、collection 和 predicate
的含义与 try-completion 中相同(see 基础补全函数),
参数 point 是光标在 string 中的位置。
每个函数在完成自身工作时应返回非 nil 值,
无法完成时返回 nil(例如,按照该补全风格无法对 string 进行补全)。
当用户调用诸如 minibuffer-complete 之类的补全命令时(see 执行补全的小缓冲命令),
Emacs 会查找 completion-styles 中列出的第一个风格,并调用其 try-completion 函数。
如果该函数返回 nil,Emacs 会转向列表中的下一个补全风格并调用其 try-completion 函数,
依此类推,直到某个 try-completion 函数成功执行补全并返回非 nil 值。
列出补全项时也会通过 all-completions 函数采用类似流程。
有关可用补全风格的说明,参见 Completion Styles in The GNU Emacs Manual。
该变量指定在对特定类型文本进行补全时所使用的特殊补全风格及其他补全行为。
其值应为一个 alist,元素形式为 (category . alist)。
category 是一个符号,描述正在补全的内容类型;
目前已定义的类别有 buffer、file 和 unicode-name,
但也可以通过专用补全函数定义其他类别(see 可编程补全)。
alist 是一个关联列表,描述对应类别下补全应如何行为。
支持的 alist 键如下:
styles值应为一个补全风格(符号)列表。
cycle值应为该类别对应的 completion-cycle-threshold 值
(see Completion Options in The GNU Emacs Manual)。
cycle-sort-function循环补全时用于排序条目的函数。
display-sort-function在 *Completions* 缓冲区中对条目排序的函数。
可选值包括:nil,表示使用元数据中的排序函数,
若元数据中为 nil 则回退到 completions-sort;
identity,表示完全不排序,保留原始顺序;
或 completions-sort 中使用的其他值
(see Completion Options in The GNU Emacs Manual)。
group-function对补全项进行分组的函数。
annotation-function为补全项添加注释的函数。
affixation-function为补全项添加前缀和后缀的函数。
完整的元数据条目列表参见 可编程补全。
该变量用于指定当前补全命令的额外属性。 它旨在由专用补全命令通过 let 绑定使用。 其值应为属性与值成对组成的列表。支持以下属性:
:category值应为一个符号,描述补全函数试图补全的文本类型。
如果该符号与上述 completion-category-overrides 中的某个键匹配,
则覆盖常规的补全行为。
:annotation-function值应为一个在补全缓冲区中添加注释的函数。
该函数必须接受一个参数(补全项),
并返回 nil 或一个显示在补全项旁边的字符串。
除非该函数自行对注释后缀字符串设置 face,
否则默认会为该字符串应用 completions-annotations face。
:affixation-function值应为一个为补全项添加前缀和后缀的函数。
该函数必须接受一个参数(补全项列表),
并返回一个带注释的补全项列表。
返回列表中的每个元素必须是一个三元素列表:
补全项、前缀字符串、后缀字符串。
该函数优先级高于 :annotation-function。
:group-function对补全项进行分组的函数。
:display-sort-function在 *Completions* 缓冲区中对条目排序的函数。
:cycle-sort-function循环补全时用于排序条目的函数。
:exit-function值应为执行补全后运行的函数。
该函数应接受两个参数:string 和 status。
其中 string 是字段补全后的文本,
status 表示所发生的操作类型:
finished 表示文本已补全完成;
sole 表示文本无法进一步补全但补全过程尚未结束;
exact 表示文本是合法补全项但仍可继续补全。
有时无法或不方便预先创建包含所有预期补全项的 alist 或 obarray。 在这种情况下,你可以提供自己的函数来计算给定字符串的补全。 这被称为 可编程补全。 Emacs 在补全文件名(see 文件名补全)等许多场景中都会使用可编程补全。
要使用此功能,需将一个函数作为 collection 参数传递给 completing-read。
completing-read 会将你的补全函数传递给 try-completion、
all-completions 以及其他基础补全函数,由你的函数完成全部工作。
补全函数应当接受三个参数:
nil。
该函数应当对每个可能的匹配项调用谓词,
若谓词返回 nil 则忽略该匹配项。
nil指定执行 try-completion 操作。
若无匹配项,函数应返回 nil;
若指定字符串是唯一且精确的匹配,返回 t;
否则返回所有匹配项的最长公共前缀子串。
t指定执行 all-completions 操作。
函数应返回指定字符串的所有可能补全项列表。
lambda指定执行 test-completion 操作。
若指定字符串是某个补全候选项的精确匹配,函数应返回 t,否则返回 nil。
(boundaries . suffix)指定执行 completion-boundaries 操作。
函数应返回 (boundaries start . end),
其中 start 是指定字符串中起始边界的位置,
end 是 suffix 中结束边界的位置。
如果 Lisp 程序返回了非平凡边界,
必须确保 all-completions 操作与其保持一致。
all-completions 返回的补全项应只对应补全边界所覆盖的前缀与后缀部分。
补全边界的确切预期语义参见 See 基础补全函数。
metadata ¶请求获取当前补全状态的相关信息。
返回值应具有形式 (metadata . alist),
其中 alist 是一个关联列表,其元素在下面说明。
如果标志是其他值,补全函数应返回 nil。
下面是补全函数在响应 metadata 标志时可以返回的元数据条目列表:
category ¶值应为一个符号,描述补全函数试图补全的文本类型。
如果该符号与 completion-category-overrides 中的某个键匹配,
则覆盖常规补全行为。See 补全相关变量。
annotation-function ¶值应为一个用于对补全项进行 注释(annotating) 的函数。
该函数接受一个参数 string,即一个可能的补全项,
并返回一个字符串,显示在 *Completions* 缓冲区中补全字符串的后面。
除非该函数自行对注释后缀字符串设置 face,
否则默认会为该字符串应用 completions-annotations face。
affixation-function ¶值应为一个用于为补全项添加前缀和后缀的函数。
该函数接受一个参数 completions,即补全项列表,
并返回同样格式的补全项列表,其中每个元素是一个三元素列表:
补全项、在 *Completions* 缓冲区中显示在补全字符串前的前缀、
以及显示在补全字符串后的后缀。
该函数优先级高于 annotation-function。
group-function ¶值应为一个用于对补全候选项分组的函数。
该函数必须接受两个参数:completion(补全候选项)
和 transform(布尔标志)。
若 transform 为 nil,函数必须返回该候选项所属分组的标题,
返回的标题也可以是 nil。
否则函数必须返回转换后的候选项。
转换操作可以例如去掉冗余前缀,该前缀会显示在分组标题中。
display-sort-function ¶值应为一个用于对补全项排序的函数。 该函数接受一个参数(补全字符串列表),并返回排序后的补全字符串列表。 允许破坏性地修改输入列表。
cycle-sort-function ¶当 completion-cycle-threshold 非 nil
且用户正在循环切换补全候选项时,用于对补全项排序的函数。
See Completion Options in The GNU Emacs Manual。
其参数列表与返回值和 display-sort-function 相同。
该函数是编写可编程补全函数的便捷方式。
参数 function 应是一个单参数函数,参数为字符串,
返回包含所有可能补全项的补全表(see 基础补全函数)。
function 返回的表中也可以包含与参数字符串不匹配的元素,
它们会被 completion-table-dynamic 自动过滤掉。
特别地,function 可以忽略其参数并返回所有可能补全项的完整列表。
你可以将 completion-table-dynamic 看作
function 与可编程补全函数接口之间的转换器。
如果可选参数 switch-buffer 非 nil,
且补全在小缓冲区中执行,
调用 function 时会将当前缓冲区设为进入小缓冲区的源缓冲区。
completion-table-dynamic 的返回值是一个函数,
可用作 try-completion 和 all-completions 的第二个参数。
注意,该函数总是返回空元数据和平凡边界。
这是 completion-table-dynamic 的包装器,
会保存上一次的参数与结果对。
这意味着使用相同参数的多次查找只需调用一次 function。
当涉及较慢操作(如调用外部进程)时,这会很有用。
虽然补全通常在小缓冲区中完成,但补全机制也可用于普通 Emacs 缓冲区中的文本。
在许多主模式中,缓冲区内补全由命令 C-M-i 或 M-TAB 执行,
该命令绑定到 completion-at-point。See Symbol Completion in The GNU Emacs Manual。
该命令使用异常钩子变量 completion-at-point-functions:
该异常钩子的值应为一个函数列表,用于计算补全表(see 基础补全函数), 以对光标处的文本进行补全。主模式可使用它提供特定于模式的补全表(see 主模式编码规范)。
当命令 completion-at-point 运行时,它会逐个调用列表中的函数,不带参数。
每个函数应返回 nil,除非它能够且希望负责光标处文本的补全数据。
否则应返回如下形式的列表:
(start end collection . props)
start 和 end 界定待补全的文本(必须包含光标)。
collection 是用于补全该文本的补全表,其形式适合作为 try-completion 的第二个参数传入(see 基础补全函数);
补全候选项将按照 completion-styles 中定义的补全风格以常规方式从该补全表生成(see 补全相关变量)。
props 是附加信息的属性列表;completion-extra-properties 中的所有属性均被识别(see 补全相关变量),
此外还支持以下属性:
:predicate值应为一个谓词,补全候选项必须满足该谓词。
:exclusive若值为 no,则当补全表无法匹配光标处文本时,
completion-at-point 会继续尝试 completion-at-point-functions 中的下一个函数,
而不是报告补全失败。
该钩子上的函数通常应快速返回,因为它们可能被频繁调用(例如从 post-command-hook)。
如果生成补全列表是开销较大的操作,强烈建议为 collection 提供一个函数。
Emacs 内部可能会多次调用 completion-at-point-functions 中的函数,
但仅在部分调用中关心 collection 的值。
通过为 collection 提供函数,Emacs 可以将补全生成推迟到必要时。
你可以使用 completion-table-dynamic 创建包装函数:
;; Avoid this pattern.
(let ((beg ...) (end ...) (my-completions (my-make-completions)))
(list beg end my-completions))
;; Use this instead.
(let ((beg ...) (end ...))
(list beg
end
(completion-table-dynamic
(lambda (_)
(my-make-completions)))))
此外,collection 通常不应基于 start 到 end 之间的当前文本进行预先过滤,
因为根据其决定使用的补全风格来执行过滤是 completion-at-point-functions 调用者的职责。
completion-at-point-functions 中的函数也可以返回一个函数,
而不是上面描述的列表。在这种情况下,会调用该返回的函数(无参数),
由它完全负责执行补全。我们不鼓励这种用法;
它仅用于帮助将旧代码迁移到使用 completion-at-point。
completion-at-point 会使用 completion-at-point-functions 中
第一个返回非 nil 值的函数,其余函数不会被调用。
上述 :exclusive 说明的情况除外。
下面的函数提供了一种便捷方式,对 Emacs 缓冲区中任意一段文本执行补全:
该函数使用 collection 对当前缓冲区中 start 到 end 位置之间的文本进行补全。
参数 collection 的含义与 try-completion 中相同(see 基础补全函数)。
该函数直接将补全文本插入当前缓冲区。
与 completing-read 不同(see 补全与小缓冲),它不会激活小缓冲区。
要使该函数正常工作,光标必须位于 start 和 end 之间。
本节描述用于向用户提出是/否问题的函数。
函数 y-or-n-p 只需单个字符即可回答;
适用于误操作不会造成严重后果的问题。
yes-or-no-p 适用于更重要的问题,因为它需要三到四个字符才能回答。
如果这两个函数中的任何一个在通过鼠标或其他窗口系统操作调用的命令中,
或者在通过菜单调用的命令中被调用,那么在支持对话框的情况下,
它们会使用对话框或弹出菜单提问。否则使用键盘输入。
你可以在调用周围将 last-nonmenu-event 绑定到合适的值,
强制使用鼠标或键盘输入——绑定为 t 强制键盘交互,
绑定为列表则强制使用对话框。
yes-or-no-p 和 y-or-n-p 均使用小缓冲区。
该函数向用户提出问题,期望在小缓冲区中输入。
如果用户输入 y,返回 t;
如果输入 n,返回 nil。
该函数还接受 SPC 表示是,DEL 表示否。
它接受 C-] 和 C-g 退出,
因为问题使用小缓冲区,因此用户可能会尝试用 C-] 退出。
答案是单个字符,无需按 RET 结束。大小写等效。
“提出问题”是指在小缓冲区中打印 prompt, 后跟字符串 ‘(y or n) ’。 如果输入不是预期答案之一(y、n、SPC、 DEL 或可退出的按键),函数会提示 ‘Please answer y or n.’ 并重复请求。
如果 prompt 是非空字符串,且以非空格字符结尾, 则会向其追加一个 ‘SPC’ 字符。
该函数实际使用小缓冲区,但不允许编辑答案。 提问时光标会移至小缓冲区。
答案及其含义(即使是 ‘y’ 和 ‘n’)并非固定,
而是由键盘映射 query-replace-map 指定(see Search and Replace)。
特别地,如果用户输入特殊响应 recenter、scroll-up、
scroll-down、scroll-other-window 或
scroll-other-window-down(在 query-replace-map 中
分别绑定到 C-l、C-v、M-v、C-M-v 和 C-M-S-v),
该函数会执行指定的窗口居中或滚动操作,然后重新提问。
如果在调用 y-or-n-p 时将 help-form(see 帮助函数)
绑定到非 nil 值,那么按下 help-char
会使其求值 help-form 并显示结果。
help-char 会自动添加到 prompt 中。
与 y-or-n-p 类似,区别在于如果用户在 seconds 秒内未回答,
该函数停止等待并返回 default。
它通过设置定时器工作;参见 Timers for Delayed Execution。
参数 seconds 应为数字。
该函数向用户提出问题,期望在小缓冲区中输入。
如果用户输入 ‘yes’,返回 t;
如果输入 ‘no’,返回 nil。
用户必须按 RET 确认回答。大小写等效。
yes-or-no-p 首先在小缓冲区显示 prompt,
后跟 yes-or-no-prompt 的值 (默认 ‘(yes or no) ’)。
用户必须输入预期回答之一;否则函数提示 ‘Please answer yes or no.’,
等待约两秒后重复请求。
如果 prompt 是非空字符串,且以非空格字符结尾, 则会向其追加一个 ‘SPC’ 字符。
yes-or-no-p 比 y-or-n-p 要求用户更多操作,
适用于更关键的决策。
示例:
(yes-or-no-p "Do you really want to remove everything? ") ;; After evaluation of the preceding expression, ;; the following prompt appears, ;; with an empty minibuffer:
---------- Buffer: minibuffer ---------- Do you really want to remove everything? (yes or no) ---------- Buffer: minibuffer ----------
如果用户先输入 y RET,这是无效的, 因为该函数要求完整单词 ‘yes’,它会显示以下提示,中间短暂停顿:
---------- Buffer: minibuffer ---------- Please answer yes or no. Do you really want to remove everything? (yes or no) ---------- Buffer: minibuffer ----------
本节描述用于向用户提出更复杂问题或多个同类问题的功能接口。
当你需要连续提出一系列相似问题时(例如逐个询问“是否保存此缓冲区?”),
应当使用 map-y-or-n-p 批量处理这些问题,而非逐个单独提问。
这能为用户提供便捷操作,比如一次性答复所有问题。
该函数向用户发起一系列提问,针对每个问题在回显区读取单个字符作为答复。
参数 list 指定要提问的对象集合,可为对象列表或生成器函数:
若为列表,则依次遍历列表中的对象;
若为函数,则无参调用该函数,返回下一个待提问对象;返回 nil 时终止提问。
参数 prompter 定义单个问题的生成方式: 若为字符串,问题文本通过格式化生成:
(format prompter object)
其中 object 是从 list 获取的当前待提问对象(format 用法见 See 格式化字符串)。
若为函数(单参数,参数为待提问对象),返回值规则:
返回字符串:作为向用户显示的问题文本;
返回 t:无需询问用户,直接处理该对象;
返回 nil:静默忽略该对象。
参数 actor 定义用户答复“是”时的处理逻辑,为单参数函数, 会以 list 中每个用户确认处理的对象为参数调用。
可选参数 help 若提供,需为如下格式的列表:
(singular plural action)
其中: singular:描述单个待处理对象的单数名词字符串; plural:对应的复数名词字符串; action:描述 actor 操作行为的及物动词。
若未指定 help,默认值为 ("object" "objects" "act on").。
每次提问时,用户可输入以下答复:
处理当前对象
跳过当前对象
处理剩余所有对象
退出(跳过剩余所有对象)
处理当前对象后退出
获取帮助信息
上述答复与 query-replace 兼容,其语义由键盘映射 query-replace-map 定义
(同时适用于 map-y-or-n-p 和 query-replace,详见 Search and Replace)。
可选参数 action-alist 用于扩展自定义答复,格式为 alist,元素结构:
(char function help)。
char:自定义答复字符;
function:单参数处理函数(参数为当前对象);
返回非 nil:视为处理完成,继续下一个对象;
返回 nil:重复当前对象的提问;
help:该答复的帮助说明文本(用户请求帮助时显示)。
默认情况下,该函数在提问时会绑定 cursor-in-echo-area 变量;
若 no-cursor-in-echo-area 非 nil,则不执行此绑定。
调用场景适配规则:
若在鼠标操作/菜单触发的命令中调用,且系统支持对话框,则使用对话框/弹出菜单提问。
可通过绑定 last-nonmenu-event 强制交互方式:
绑定为 t:强制键盘交互;
绑定为列表:强制对话框交互。
函数 map-y-or-n-p 返回值为实际处理的对象数量。
若需提出超过两个选项的问题,应使用 read-answer 函数。
该函数会使用 question 中的文本提示用户,其中 question 应以 ‘SPC’(空格)字符结尾。函数会将 answers 中的可选响应追加到 question 末尾,从而在提示信息中包含这些选项。 answers 中的可选响应以关联列表(alist)形式提供,其元素格式如下:
(long-answer short-answer help-message)
其中:long-answer 是用户响应的完整文本(字符串类型);
short-answer 是该响应的简写形式(单个字符或功能键);
help-message 是描述该答案含义的文本。
若变量 read-answer-short 的值非 nil,则提示信息会显示可选答案的简写形式,
且期望用户输入提示中显示的单个字符/按键;否则提示信息会显示答案的完整形式,
且期望用户输入其中一个答案的完整文本并按下 RET(回车键)确认。
若 use-dialog-box 的值非 nil,且该函数由鼠标事件触发调用,
则问题和答案会显示在图形界面(GUI)对话框中。
无论提示信息中显示的是完整答案还是简写答案,也无论用户输入的是哪种形式, 该函数最终都会返回用户所选答案对应的 long-answer 文本。
以下是该函数的使用示例:
(let ((read-answer-short t))
(read-answer "Foo "
'(("yes" ?y "perform the action")
("no" ?n "skip to the next")
("all" ?! "perform for the rest without more questions")
("help" ?h "show help")
("quit" ?q "exit"))))
该函数使用迷你缓冲区(minibuffer)读取并返回单个
字符。可选地,它会忽略所有不属于 chars 的输入(chars 是一个包含所有可接受字符的列表)。
history 参数指定要使用的历史列表符号;若省略该参数或其值为
nil,则该函数不会使用历史记录功能。
在调用 read-char-from-minibuffer 时,若将
help-form(see 帮助函数)绑定为非 nil 的值,
则按下 help-char 会触发对 help-form 的求值,并显示求值结果。
若要读取密码并传递给其他程序,可以使用
函数 read-passwd。
该函数读取密码,使用 prompt 作为提示信息。用户输入时
不会回显密码本身;而是对密码中的每个字符回显
‘*’。如果希望使用其他字符来隐藏密码,
可以将变量 read-hide-char 临时绑定为该字符。
可选参数 confirm 若非 nil,则表示需要读取两次密码
并要求两次输入必须一致。如果不一致,用户必须反复输入,
直到最后两次匹配为止。
可选参数 default 指定当用户输入为空时返回的默认密码。
如果 default 为 nil,则此时 read-passwd
返回空字符串。
该函数使用一个次要模式 read-passwd-mode。它在迷你缓冲区中
绑定了两个按键:C-u(delete-minibuffer-contents)
用于删除密码,TAB(read-passwd--toggle-visibility)
用于切换密码的可见性。在模式行的 global-mode-string
中还会显示一个额外图标。使用 mouse-1 点击该图标同样可以
切换密码的可见性。
本节描述一些用于迷你缓冲区中的命令。
该命令退出当前激活的迷你缓冲区。它通常绑定在 迷你缓冲区本地按键映射中。如果当前缓冲区是迷你缓冲区 但并非激活的迷你缓冲区,该命令会抛出错误。
该命令插入键盘上最后输入的字符(保存在 last-command-event 中;
see 来自命令循环的信息),然后退出激活的迷你缓冲区。
该命令将迷你缓冲区内容替换为第 n 个更早的历史条目。
该命令将迷你缓冲区内容替换为第 n 个更新的历史条目。 历史位置可以超出当前位置,并触发“未来历史” (see 使用迷你缓冲区读取文本字符串)。
该命令将迷你缓冲区内容替换为第 n 个更早、且匹配 pattern (正则表达式)的历史条目。
该命令将迷你缓冲区内容替换为第 n 个更新、且匹配 pattern (正则表达式)的历史条目。
该命令将迷你缓冲区内容替换为第 n 个更早、 且能补全光标前迷你缓冲区当前内容的历史条目。
该命令将迷你缓冲区内容替换为第 n 个更新、 且能补全光标前迷你缓冲区当前内容的历史条目。
该函数将迷你缓冲区历史中的条目放入迷你缓冲区。
参数 nabs 以降序指定绝对历史位置,其中 0 表示当前条目,
正数 n 表示第 n 个更早的条目。
若 NABS 为负数 -n,则表示“未来历史”中的第 n 项。
当该函数到达由 read-from-minibuffer(see 使用迷你缓冲区读取文本字符串)
和 completing-read(see 补全与小缓冲)
提供的默认值末尾时,会将补全候选项加入“未来历史”,
参见 minibuffer-default-add-function。
这些函数用于访问和选中迷你缓冲区窗口、判断它们是否处于激活状态, 以及控制它们的自动调整大小行为。
该函数返回用于框架 frame 的迷你缓冲区窗口。
如果 frame 为 nil,则表示当前选中的框架。
注意,某个框架所使用的迷你缓冲区窗口不一定属于该框架本身——
一个没有自身迷你缓冲区的框架,必然会使用其他框架的迷你缓冲区窗口。
无迷你缓冲区框架所使用的迷你缓冲区窗口,可以通过设置该框架的
minibuffer 框架参数来更改(see Buffer Parameters)。
该函数将 window 指定为要使用的迷你缓冲区窗口。 这会影响在不调用常规迷你缓冲区命令的情况下向其中放入文本时, 迷你缓冲区的显示位置。它对常规的迷你缓冲区输入函数没有影响, 因为这些函数都会先根据当前选中框架选择对应的迷你缓冲区窗口。
如果 window 是迷你缓冲区窗口,该函数返回 t。
window 的默认值为当前选中窗口。
下面的函数返回显示当前激活迷你缓冲区的窗口。
该函数返回当前激活迷你缓冲区所在的窗口;
如果没有激活的迷你缓冲区,则返回 nil。
仅通过将某个窗口与 (minibuffer-window) 的结果比较,
不足以判断该窗口是否显示当前激活的迷你缓冲区,
因为当存在多个框架时,可能会有多个迷你缓冲区窗口。
如果 window 显示的是当前激活的迷你缓冲区,
该函数返回非 nil。
下面两个选项控制迷你缓冲区窗口是否自动调整大小, 以及调整过程中的最大高度。
该选项指定迷你缓冲区窗口是否自动调整大小。默认值为 grow-only,
表示迷你缓冲区窗口默认会自动扩展以适应所显示的文本,
并在迷你缓冲区清空后立即收缩回一行高度。
如果值为 t,Emacs 会始终尝试让迷你缓冲区窗口的高度
适配其显示的文本(最小高度为一行)。
如果值为 nil,迷你缓冲区窗口不会自动改变大小。
这种情况下可以使用窗口大小调整命令(see Resizing Windows)
来手动调整其高度。
该选项为迷你缓冲区窗口的自动调整大小设置最大高度限制。 浮点数指定的最大高度为框架高度的比例; 整数指定的最大高度以框架的标准字符高度为单位(see Frame Font)。 默认值为 0.25。
注意,上述两个变量的值只在显示时生效,
因此在产生回显区消息的代码周围对它们进行临时绑定不会起作用。
如果希望在显示长消息时阻止迷你缓冲区窗口调整大小,
请改为绑定变量 message-truncate-lines(see Echo Area Customization)。
选项 resize-mini-windows 不影响仅迷你缓冲区框架的行为(see Frame Layout)。
下面的选项同样支持对这类框架进行自动调整大小。
如果该选项为 nil,仅迷你缓冲区框架不会被自动调整大小。
如果该选项是一个函数,则会以需要调整大小的仅迷你缓冲区框架 作为唯一参数调用该函数。调用该函数时, 该框架的迷你缓冲区窗口所对应的缓冲区, 是该窗口下次重新刷新时将要显示内容的缓冲区。 该函数应以合适的方式让框架适配缓冲区内容。
任何其他非 nil 值表示通过调用 fit-mini-frame-to-buffer
来自动调整仅迷你缓冲区框架的大小。该函数行为类似
fit-frame-to-buffer(see Resizing Windows),
但不会从缓冲区文本中去除开头或结尾的空行。
这些函数用于获取迷你缓冲区的提示字符串和可编辑内容。
该函数返回当前激活迷你缓冲区的提示字符串。
如果没有激活的迷你缓冲区,则返回 nil。
如果当前处于迷你缓冲区中,该函数返回迷你缓冲区提示字符串的结束位置。 否则返回当前缓冲区的最小有效位置。
如果当前处于迷你缓冲区中,该函数返回迷你缓冲区提示字符串 在当前显示下的宽度。否则返回 0。
如果当前处于迷你缓冲区中,该函数以字符串形式返回 迷你缓冲区的可编辑内容(即除去提示部分的所有内容)。 否则返回当前缓冲区的全部内容。
该函数与 minibuffer-contents 类似,
区别是它只复制字符本身,不复制文本属性。See Text Properties。
如果当前处于迷你缓冲区中,该命令清除迷你缓冲区的可编辑内容 (即除去提示部分的所有内容)。 否则清除当前缓冲区的全部内容。
这些函数和变量用于处理递归迷你缓冲区(see 递归编辑):
该函数返回当前迷你缓冲区的激活深度,为一个非负整数。 如果没有迷你缓冲区处于激活状态,则返回 0。
如果该变量非 nil,那么即使迷你缓冲区已激活,
你仍然可以调用使用迷你缓冲区的命令(如 find-file)。
这种调用会为新的迷你缓冲区产生一个递归编辑层级。
默认情况下,编辑内层迷你缓冲区时,外层迷你缓冲区不可见。
如果将 minibuffer-follows-selected-frame 设置为 nil,
则可以在多个框架上同时显示迷你缓冲区。
See (emacs)Basic Minibuffer。
如果该变量为 nil,则当迷你缓冲区激活时,
你无法调用迷你缓冲区相关命令,即使切换到其他窗口也不行。
如果某个命令名具有非 nil 的
enable-recursive-minibuffers 属性,
那么即使从迷你缓冲区中调用该命令,它仍然可以使用迷你缓冲区读取参数。
命令也可以在 interactive 声明中
将 enable-recursive-minibuffers 绑定为 t
来实现这一点(see 使用 interactive)。
迷你缓冲区命令 next-matching-history-element
(在迷你缓冲区中通常绑定为 M-s)就是采用后一种方式。
有时将 Emacs 作为无头服务器进程运行、 通过网络连接响应命令会很有用。 然而,Emacs 主要是一个交互式使用平台, 因此许多命令在异常情况下会向用户提示以获取反馈。 这会让这种使用场景变得困难,因为服务器进程会挂起等待用户输入。
将变量 inhibit-interaction 绑定为非 nil 值,
会让 Emacs 触发一个 inhibited-interaction 错误,
而不是弹出提示,服务器进程可以利用这一点来处理这些情况。
典型使用示例:
(let ((inhibit-interaction t))
(respond-to-client
(condition-case err
(my-client-handling-function)
(inhibited-interaction err))))
如果 my-client-handling-function 最终调用了
需要向用户询问信息的函数(通过 y-or-n-p 或
read-from-minibuffer 等),
则会触发 inhibited-interaction 错误。
服务器代码可以捕获该错误并将其报告给客户端。
如果 buffer-or-name 是迷你缓冲区,
该函数返回非 nil。
如果省略 buffer-or-name 或其为 nil,
则测试当前缓冲区。
当 live 非 nil 时,
仅当 buffer-or-name 是**激活的**迷你缓冲区时才返回非 nil。
该宏会先将指定的 function 加入
minibuffer-setup-hook,然后执行 body。
默认情况下,function 在
minibuffer-setup-hook 列表中的其他函数**之前**调用;
但如果 function 形式为
(:append func),则 func
会在其他钩子函数 之后 调用。
body 中的代码不应多次使用迷你缓冲区。 如果迷你缓冲区被递归重入, function 只会对 最外层 的迷你缓冲区调用一次。
如果该变量的值非 nil,则它应该是一个窗口对象。
当在迷你缓冲区中调用函数 scroll-other-window 时,
会滚动该窗口(see Textual Scrolling)。
该函数返回迷你缓冲区窗口被选中之前刚刚被选中的窗口。
如果当前选中窗口不是迷你缓冲区窗口,则返回 nil。
该函数与 message 类似(see Displaying Messages in the Echo Area),
但当用户在迷你缓冲区中输入时(通常是 Emacs 提示用户输入时),
它会以特殊方式显示消息。
当迷你缓冲区为当前缓冲区时,该函数会将 string 指定的消息
临时显示在迷你缓冲区文本末尾,
从而避免回显区的消息显示覆盖迷你缓冲区内容。
它会将消息显示几秒钟,或直到下一个输入事件到达,以先到者为准。
变量 minibuffer-message-timeout 指定无输入时的等待秒数,
默认为 2。
如果 args 非 nil,则实际消息通过
将 string 和 args 传入 format-message 得到。
See 格式化字符串。
如果在迷你缓冲区不是当前缓冲区时调用,
该函数只会调用 message,
因此 string 会显示在回显区。
这是未激活迷你缓冲区所使用的主模式。
它使用按键映射 minibuffer-inactive-mode-map。
当迷你缓冲区位于单独框架中时,该模式会很有用。
See Minibuffers and Frames。
该次要模式让在迷你缓冲区中编辑正则表达式更加方便。
它通过 show-paren-mode 和 blink-matching-paren
以友好方式高亮括号,避免报告虚假括号不匹配,
并让 S 表达式导航更直观。
默认情况下,只有特定的迷你缓冲区提示在迷你缓冲区激活时
会自动启用 minibuffer-regexp-mode 的便捷功能。
可以通过 minibuffer-regexp-prompts 自定义这个提示列表。
该变量保存一组正则表达式,
用于在迷你缓冲区中激活 minibuffer-regexp-mode 的功能。
仅当迷你缓冲区提示匹配列表中的某一正则表达式时,
才会启用该模式的功能。
当你运行 Emacs 时,它几乎会立即进入 编辑器命令循环(editor command loop)。 该循环读取按键序列,执行其定义,并显示结果。 本章将描述这些过程的实现方式,以及允许 Lisp 程序完成这些操作的子例程。
命令循环首先必须读取按键序列,它是一组可转换为命令的输入事件。
这一过程通过调用函数 read-key-sequence 完成。
Lisp 程序也可以调用该函数(see 读取按键序列)。
它们还可以使用 read-key 或 read-event 在更低层级读取输入(see 读取单个事件),
或使用 discard-input 丢弃待处理输入(see 事件输入的杂项功能)。
按键序列通过当前生效的按键映射转换为命令。
关于转换方式的说明,参见 See 按键查找。
结果应为键盘宏或可交互式调用的函数。
如果按键是 M-x,则读取另一个命令的名称并执行。
这由命令 execute-extended-command 完成(see 交互式调用)。
在执行命令之前,Emacs 会运行 undo-boundary 以创建撤销边界。
参见 See Maintaining Undo Lists。
为执行命令,Emacs 首先通过调用 command-execute 读取其参数(see 交互式调用)。
对于用 Lisp 编写的命令,interactive 声明指明如何读取参数。
这可能会使用前缀参数(see 前缀命令参数),
或在小缓冲中通过提示读取(see 迷你缓冲区)。
例如,命令 find-file 的 interactive 声明指明使用小缓冲读取文件名。
find-file 的函数体本身不使用小缓冲,
因此如果你从 Lisp 代码中以函数形式调用 find-file,
必须将文件名字符串作为普通 Lisp 函数参数提供。
如果命令是键盘宏(即字符串或向量),
Emacs 使用 execute-kbd-macro 执行它(see 键盘宏)。
这个常规钩子由编辑器命令循环在执行每个命令之前运行。
此时,this-command 包含即将运行的命令,
last-command 描述上一个命令。
参见 See 来自命令循环的信息。
这个常规钩子由编辑器命令循环在执行每个命令之后运行(包括因退出或错误提前终止的命令)。
此时,this-command 指向刚刚运行的命令,
last-command 指向前一个命令。
当 Emacs 首次进入命令循环时也会运行该钩子
(此时 this-command 和 last-command 均为 nil)。
运行 pre-command-hook 和 post-command-hook 期间会禁止退出操作。
如果执行这些钩子时发生错误,不会终止钩子的执行;
相反,错误会被静默处理,发生错误的函数会从钩子中移除。
进入 Emacs 服务器的请求(see Emacs Server in The GNU Emacs Manual) 与键盘命令一样,会运行这两个钩子。
注意,当缓冲区文本包含极长行时,
这两个钩子的调用方式如同在 with-restriction 形式中(see Narrowing),
带有 long-line-optimizations-in-command-hooks 标签,
并且缓冲区被缩小到光标附近的一段区域。
特殊形式 interactive 将 Lisp 函数转变为命令。
interactive 形式必须位于函数体的顶层,通常作为函数体中的第一个形式;
这对 lambda 表达式(see Lambda 表达式)和 defun 形式(see 定义函数)均适用。
该形式在函数实际执行期间不做任何操作;它的存在只是一个标记,
告诉 Emacs 命令循环该函数可以被交互式调用。
interactive 形式的参数指定交互式调用时应如何读取参数。
另外,也可以在函数符号的 interactive-form 属性中指定 interactive 形式。
该属性的非 nil 值优先级高于函数体本身中的任何 interactive 形式。
此特性很少使用。
有时,某个函数仅用于交互式调用,从不从 Lisp 中直接调用。
在这种情况下,可以直接或通过 declare(see declare 形式)
为函数设置非 nil 的 interactive-only 属性。
如果该命令从 Lisp 中被调用,字节编译器会发出警告。
describe-function 的输出也会包含类似信息。
该属性的值可以是:
一个字符串,字节编译器会直接在警告中使用它(应以句号结尾,且不以大写字母开头,
例如 "use (system-name) instead.");
t;
或任何其他符号,该符号应是可在 Lisp 代码中使用的替代函数。
泛型函数(see 泛型函数)无法通过添加 interactive 形式转变为命令。
interactive ¶本节介绍如何编写 interactive 形式,使 Lisp 函数成为可交互式调用的命令,
以及如何检查命令的 interactive 形式。
该特殊形式声明一个函数是命令,因此可以被交互式调用(通过 M-x 或输入绑定到它的按键序列)。 参数 arg-descriptor 声明命令在交互式调用时如何计算参数。
命令可以像其他函数一样从 Lisp 程序中调用, 但此时由调用者提供参数,arg-descriptor 不起作用。
interactive 形式必须位于函数体的顶层,
或在函数符号的 interactive-form 属性中(see 符号属性)。
它之所以有效,是因为命令循环在调用函数之前会查找它(see 交互式调用)。
一旦函数被调用,其所有体形式都会被执行;
此时,如果 interactive 形式出现在函数体内,
该形式仅返回 nil,甚至不计算其参数。
modes 列表用于指定命令适用于哪些模式。 关于指定 modes 的效果及使用时机,详见 为命令指定适用模式。
按照惯例,应将 interactive 形式放在函数体中,作为第一个顶层形式。
如果符号的 interactive-form 属性和函数体中同时存在 interactive 形式,
前者优先级更高。
interactive-form 符号属性可用于为已有函数添加交互式形式,
或在不重新定义函数的情况下修改其交互式参数处理方式。
参数 arg-descriptor 有三种可能:
nil;此时命令不带参数调用。
如果命令需要一个或多个参数,这会迅速导致错误。
interactive 的代码字符)和可选的提示字符串组成
(某些代码字符会使用提示,有些则忽略)。示例:
(interactive "P\nbFrobnicate buffer: ")
代码字符 ‘P’ 将命令的第一个参数设为原始命令前缀(see 前缀命令参数)。 ‘bFrobnicate buffer: ’ 以 ‘Frobnicate buffer: ’ 提示用户输入已有缓冲区的名称, 该名称成为第二个也是最后一个参数。
提示字符串中可以使用 ‘%’ 将之前的参数值(从第一个参数开始)包含到提示中。
这通过 format-message 实现(see 格式化字符串)。
例如,下面可以读取一个已有缓冲区的名称,再读取要赋予该缓冲区的新名称:
(interactive "bBuffer to rename: \nsRename buffer %s to: ")
如果字符串以 ‘*’ 开头,则当缓冲区为只读时会发出错误信号。
如果字符串以 ‘@’ 开头,并且用于调用命令的按键序列包含任意鼠标事件, 则在运行命令前会选中与这些事件中的第一个相关联的窗口。
如果字符串以 ‘^’ 开头,并且命令是通过shift 转换调用的,
则在运行命令前设置标记并临时激活区域,或扩展已激活的区域。
如果命令不是通过 shift 转换调用,且区域处于临时激活状态,
则在运行命令前取消激活区域。
shift 转换在用户层面由 shift-select-mode 控制;
详见 Shift Selection in The GNU Emacs Manual。
可以同时使用 ‘*’、‘@’ 和 ‘^’,顺序无关紧要。 实际的参数读取由提示字符串的剩余部分(从第一个不是 ‘*’、‘@’ 或 ‘^’ 的字符开始)控制。
将光标位置或标记作为参数值也很常见, 但如果这样做**并且**读取输入(无论是否使用小缓冲), 务必在读取后获取光标或标记的整数值。 当前缓冲区可能接收子进程输出; 如果命令在等待输入时子进程输出到达,可能会改变光标和标记的位置。
下面是 不应 这样做的示例:
(interactive
(list (region-beginning) (region-end)
(read-string "Foo: " nil 'my-history)))
下面是正确做法,在读取键盘输入后再获取光标和标记:
(interactive (let ((string (read-string "Foo: " nil 'my-history))) (list (region-beginning) (region-end) string)))
警告:参数值不应包含任何无法被打印和读取的数据类型。
某些工具会将 command-history 保存到文件中,以便在后续会话中读取;
如果命令的参数包含以 ‘#<…>’ 语法打印的数据类型,这些工具将无法工作。
不过也有少数例外:可以使用有限的表达式,
如 (point)、(mark)、(region-beginning) 和 (region-end),
因为 Emacs 会特殊识别它们,并将表达式(而非其值)存入命令历史。
要判断你写的表达式是否属于这些例外,运行命令后查看 (car command-history)。
该函数返回 function 的 interactive 形式。
如果 function 是可交互式调用的函数(see 交互式调用),
返回值是命令的 interactive 形式 (interactive spec),
它指定如何计算参数。否则返回 nil。
如果 function 是符号,则使用其函数定义。
当作用于 OClosure 时,工作会委托给泛型函数 oclosure-interactive-form。
与 interactive-form 类似,该函数接收命令并返回其交互式形式。
区别在于它是泛型函数,且仅在 function 是 OClosure 时被调用(see 开放式闭包)。
其目的是让某些 OClosure 类型可以动态计算它们的交互式形式,
而不是在某个槽位中保存它。
例如,该函数用于 kmacro 函数以减少内存占用,
因为它们共享同一个交互式形式。
它也用于 advice 函数,其中交互式形式从其组件的交互式形式计算而来,
从而使计算更惰性,并在某个组件被重新定义时正确调整交互式形式。
interactive 的代码字符 ¶下面的代码字符说明中包含若干关键词,其定义如下:
提供补全功能。TAB、SPC 和 RET 执行名称补全,
因为参数是通过 completing-read 读取的(see 补全)。
? 显示可能的补全列表。
要求输入已有对象的名称。不接受无效名称; 如果当前输入不合法,退出小缓冲的命令不会生效。
如果用户在小缓冲中未输入任何内容,则使用某种默认值。 默认值取决于代码字符。
该代码字符不读取任何输入即可计算出参数。 因此,它不使用提示字符串,你提供的任何提示字符串都会被忽略。
即使该代码字符不使用提示字符串,如果它不是字符串中的最后一个代码字符, 你仍必须在其后跟随一个换行符。
代码字符后紧跟提示信息。提示在字符串结束或换行符处结束。
该代码字符仅在交互式字符串开头有意义,且不寻找提示或换行符。 它是一个单独的、独立的字符。
以下是可用于 interactive 的代码字符说明:
如果当前缓冲区为只读,则发出错误信号。特殊。
选中调用该命令的按键序列中第一个鼠标事件所对应的窗口。特殊。
如果命令是通过 Shift 转换调用的,则在运行命令前设置标记并临时激活区域, 或扩展已激活的区域。 如果命令不是通过 Shift 转换调用,且区域处于临时激活状态, 则在运行命令前取消激活区域。特殊。
函数名(即满足 fboundp 的符号)。已存在、补全、提示。
已有缓冲区的名称。默认使用当前缓冲区的名称(see 缓冲区)。 已存在、补全、默认值、提示。
缓冲区名称。缓冲区不必存在。默认使用当前缓冲区以外最近使用的缓冲区名称。 补全、默认值、提示。
字符。光标不会移入回显区。提示。
命令名(即满足 commandp 的符号)。已存在、补全、提示。
光标位置,以整数表示(see Point)。无输入输出(No I/O)。
目录。默认值为当前缓冲区的当前默认目录 default-directory(see 文件名展开相关函数)。
已存在、补全、默认值、提示。
调用该命令的按键序列中的第一个或下一个非键盘事件。 更精确地说,‘e’ 获取列表形式的事件,因此你可以查看列表中的数据。 See 输入事件。无输入输出。
‘e’ 用于鼠标事件和特殊系统事件(see 其他系统事件)。 命令接收的事件列表取决于具体事件。 See 输入事件 在对应小节中描述了每种事件的列表形式。
你可以在单个命令的交互式声明中多次使用 ‘e’。 如果调用该命令的按键序列中有 n 个列表形式的事件, 则第 n 个 ‘e’ 提供第 n 个此类事件。 非列表形式的事件(如功能键和 ASCII 字符)不计入 ‘e’ 所关注的事件。
文件名。文件不必存在。补全、默认值、提示。
文件名。文件不必存在。如果用户只输入目录名,则返回值就是该目录名, 不会在目录后附加文件名。补全、默认值、提示。
无关参数。该代码总是提供 nil 作为参数值。无输入输出。
按键序列(see 按键序列)。 它会持续读取事件,直到在当前按键映射中找到一个命令(或未定义命令)。 按键序列参数以字符串或向量表示。光标不会移入回显区。提示。
如果 ‘k’ 读取的按键序列以按下事件结束, 它还会读取并丢弃随后的释放事件。 你可以使用 ‘U’ 代码字符获取该释放事件。
这类输入用于 describe-key 和 keymap-global-set 等命令。
可用于 keymap-set 等函数的按键序列形式。
工作方式与 ‘k’ 类似,区别在于它会对按键序列中的最后一个输入事件
禁止通常用于(必要时)将未定义按键转换为已定义按键的转换(see 读取按键序列)。
因此该形式通常用于提示输入要绑定到命令的新按键序列。
标记位置,以整数表示。无输入输出。
任意文本,在小缓冲中使用当前缓冲区的输入法读取,并以字符串返回(see Input Methods in The GNU Emacs Manual)。提示。
数字,在小缓冲中读取。如果输入不是数字,用户必须重新输入。 ‘n’ 从不使用前缀参数。提示。
数字前缀参数;但如果没有前缀参数,则像 n 一样读取数字。 值始终为数字。See 前缀命令参数。提示。
数字前缀参数。(注意此 ‘p’ 为小写。)无输入输出。
原始前缀参数。(注意此 ‘P’ 为大写。)无输入输出。
光标和标记,作为两个数值参数,较小者在前。
这是唯一指定连续两个参数而非一个参数的代码字母。
如果调用命令时当前缓冲区未设置标记,将会发出错误信号。
如果临时标记模式已开启(see The Mark) — 默认即为开启 —
且用户选项 mark-even-if-inactive 为 nil,
即使标记已设置但未激活,Emacs 也会发出错误信号。无输入输出。
任意文本,在小缓冲中读取并以字符串返回(see 使用迷你缓冲区读取文本字符串)。 使用 C-j 或 RET 结束输入。 (可使用 C-q 将这两个字符之一包含到输入中。)提示。
名称在小缓冲中读取的已 intern 符号。 使用 C-j 或 RET 结束输入。 其他通常用于结束符号的字符(如空白、圆括号和方括号)在此处不结束输入。提示。
按键序列或 nil。
可在 ‘k’ 或 ‘K’ 参数之后使用,
以获取 ‘k’ 或 ‘K’ 读取按下事件后被丢弃的释放事件(如果有)。
如果没有丢弃释放事件,‘U’ 提供 nil 作为参数。无输入输出。
声明为用户选项的变量(即满足谓词 custom-variable-p)。
通过 read-variable 读取该变量。See Definition of read-variable。
已存在、补全、提示。
Lisp 对象,以其读取语法指定,以 C-j 或 RET 结束。 该对象不会被求值。See 使用迷你缓冲读取 Lisp 对象。提示。
Lisp 形式的值。‘X’ 读取方式与 ‘x’ 相同, 然后对该形式求值,使其值成为命令的参数。提示。
编码系统名称(符号)。如果用户输入空内容,参数值为 nil。
See Coding Systems。补全、已存在、提示。
编码系统名称(符号)——但仅当该命令有前缀参数时有效。
如果没有前缀参数,‘Z’ 提供 nil 作为参数值。
补全、已存在、提示。
interactive 使用示例 ¶这里是一些 interactive 的示例:
(defun foo1 () ; foo1 不带参数,
(interactive) ; 仅向前移动两个单词。
(forward-word 2))
⇒ foo1
(defun foo2 (n) ;foo2接受一个参数, (interactive "^p") ; 该参数为数字前缀参数。 ; 在shift-select-mode下, ; 会激活或扩展区域。 (forward-word (* 2 n))) ⇒ foo2
(defun foo3 (n) ; foo3 接受一个参数,
(interactive "nCount:") ; 通过迷你缓冲读取该参数。
(forward-word (* 2 n)))
⇒ foo3
(defun three-b (b1 b2 b3) "选择三个已存在的缓冲区。 将它们放入三个窗口,并选中最后一个。"
(interactive "bBuffer1:\nbBuffer2:\nbBuffer3:")
(delete-other-windows)
(split-window (selected-window) 8)
(switch-to-buffer b1)
(other-window 1)
(split-window (selected-window) 8)
(switch-to-buffer b2)
(other-window 1)
(switch-to-buffer b3))
⇒ three-b
(three-b "*scratch*" "declarations.texi" "*mail*")
⇒ nil
Emacs 中的很多命令是通用的,不与任何特定模式绑定。 例如,M-x kill-region 几乎可以在任何可编辑文本的模式中使用, 而显示信息的命令(如 M-x list-buffers)几乎可以在任何上下文使用。
但另一些命令则与特定模式紧密绑定,在该上下文之外没有意义。
例如,在 Dired 缓冲区之外使用 M-x dired-diff 只会报错。
因此 Emacs 提供了一种机制,用于指定命令 “属于(belongs)” 哪个(哪些)模式:
(defun dired-diff (...) ... (interactive "p" dired-mode) ...)
这会将该命令标记为仅适用于 dired-mode(或从 dired-mode 派生的任何模式)。
可以在 interactive 形式中指定任意数量的模式。
This will mark the command as applicable to dired-mode only (or
any modes that are derived from dired-mode). Any number of
modes can be added to the interactive form.
指定模式会影响 M-S-x(execute-extended-command-for-buffer,see 交互式调用)中的命令补全。
根据 read-extended-command-predicate 的值,它也可能影响 M-x 中的补全。
例如,当将 command-completion-default-include-p 谓词作为
read-extended-command-predicate 的值时,
M-x 不会列出被标记为特定模式专用的命令(当然,除非你正在使用该模式的缓冲区中)。
这对主模式和次要模式都生效。
(相比之下,M-S-x 总是从不适用的命令中排除补全候选。)
默认情况下,read-extended-command-predicate 为 nil,
M-x 的补全会列出所有与用户输入匹配的命令,
无论这些命令是否被标记为适用于当前缓冲区的模式。
将命令标记为适用于某个模式,还会让 C-h m 列出这些命令(如果它们未绑定到任何按键)。
如果使用这种扩展的 interactive 形式不方便
(因为代码需要在不支持扩展 interactive 形式的旧版 Emacs 中运行),
可以使用下面等价的声明(see declare 形式)代替:
(declare (modes dired-mode))
哪些命令需要标记模式在一定程度上取决于个人习惯, 但 明显只能在该模式内使用 的命令应当被标记。 这包括在其他地方调用会报错的命令, 也包括在意外模式下调用会产生破坏性效果的命令。 (这通常包括为特殊(即非编辑)模式编写的大多数命令。)
有些命令在其他模式下调用可能无害且能 “正常运行(work)”,
但如果在其他地方使用实际上没有意义,仍然应该标记模式。
例如,许多特殊模式都有绑定到 q 的退出缓冲区命令,
它们可能只输出类似 “从此模式再见(Goodbye from this mode)” 的信息,然后调用 kill-buffer。
该命令在任何模式下都能 “运行(work)”,
但几乎没有人会想在该特殊模式之外使用它。
许多模式都有一组以不同方式启动该模式的命令(例如 eww-open-in-new-buffer 和 eww-open-file)。
这类命令 绝不应该 被标记为模式专用,
因为用户几乎可以在任何上下文执行它们。
有时定义一个充当「通用调度器」的命令会很有用,
它能够根据用户需求调用一组命令中的某一个。
例如,你可能想定义一个名为 ‘open’ 的命令,
用于「打开」并显示多种不同类型的对象。
或者你可以有一个名为 ‘mua’(邮件用户代理 Mail User Agent 的缩写)的命令,
它可以通过多种邮件后端(如 Rmail、Gnus 或 MH-E)读取和发送邮件。
宏 define-alternatives 可用于定义此类 通用命令(generic commands)。
通用命令是一种交互式函数,其具体实现可根据用户偏好从多个备选方案中选择。
该宏定义新的通用命令 command,该命令可拥有多个备选实现。 参数 command 应为未加引号的符号。
调用该宏时,会创建一个交互式 Lisp 闭包(see 闭包)。
当用户首次运行 M-x command RET 时,
Emacs 会要求用户从 command 的多个备选实现中选择一个,
并为这些备选方案的名称提供补全功能。
这些名称来自宏创建的用户选项 command-alternatives(如果该选项不存在)。
为保证可用性,该变量的值应为一个关联列表(alist),
其元素格式为 (alt-name . alt-func),
其中 alt-name 是备选方案的名称,
alt-func 是选中该备选方案时要调用的交互式函数。
当用户选择某个备选方案后,Emacs 会记住该选择;
此后用户再次调用 M-x command 时,
会自动调用该选中的备选方案,无需再次提示。
若要选择不同的备选方案,可键入 C-u M-x command RET——
此时 Emacs 会再次提示选择备选方案,且新选择会覆盖之前的设置。
变量 command-alternatives 可在调用 define-alternatives 之前创建并设置合适的值;
若未提前创建,该宏会创建值为 nil 的该变量,
之后需填充描述备选方案的关联项。
希望为已有通用命令提供自定义实现的包,
可使用 autoload 标记(see 自动加载)向该关联列表中添加内容,例如:
;;;###autoload (push '("My name" . my-foo-symbol) foo-alternatives
若可选参数 customizations 非 nil,
则应由交替出现的 defcustom 关键字(通常为 :group 和 :version)
以及要添加到 defcustom command-alternatives 定义中的值组成。
以下是一个简单的通用调度器命令示例,
命令名为 open,包含 3 个备选实现:
(define-alternatives open :group 'files :version "42.1")
(setq open-alternatives
'(("file" . find-file)
("directory" . dired)
("hexl" . hexl-find-file)))
命令循环将按键序列转换为命令后,会使用函数 command-execute 调用该命令。
如果命令是一个函数,command-execute 会调用 call-interactively,
由它读取参数并执行命令。你也可以自行调用这些函数。
注意,在此上下文中,术语“命令”指可交互式调用的函数(或类函数对象)或键盘宏。 它并不指代用于调用命令的按键序列(see 按键映射)。
如果 object 是命令,此函数返回 t,否则返回 nil。
命令包括字符串和向量(被当作键盘宏)、
包含顶层 interactive 形式的 lambda 表达式(see 使用 interactive)、
由这类 lambda 表达式生成的字节码函数对象、
声明为交互式的自动加载对象(autoload 的第四个参数为非 nil),
以及一些原语函数。
此外,如果一个符号拥有非 nil 的 interactive-form 属性,
或者其函数定义满足 commandp,则该符号也被视为命令。
如果 for-call-interactively 为非 nil,
则 commandp 仅对 call-interactively 能够调用的对象返回 t——
因此不包括键盘宏。
关于使用 commandp 的实际示例,参见 访问文档字符串 中的 documentation。
此函数调用可交互式函数 command,并根据其交互式调用规范提供参数。 它返回 command 的返回值。
例如,如果你有一个如下签名的函数:
(defun foo (begin end) (interactive "r") ...)
那么执行:
(call-interactively 'foo)
会以区域(point 和 mark)作为参数调用 foo。
如果 command 不是函数或无法被交互式调用(即不是命令),则会发出错误信号。
注意,键盘宏(字符串和向量)虽然被视为命令,但不被接受,因为它们不是函数。
如果 command 是符号,call-interactively 会使用其函数定义。
如果 record-flag 为非 nil,
则此命令及其参数会被无条件加入 command-history 列表。
否则,仅当命令使用小缓冲读取参数时才会被加入。see 命令历史。
参数 keys 如果给出,应为一个向量,
用于指定当命令询问调用它的事件序列时所返回的事件。
如果 keys 被省略或为 nil,
默认使用 this-command-keys-vector 的返回值。
See Definition of this-command-keys-vector。
此函数的工作方式类似 funcall(see 调用函数),
但会让调用看起来像是交互式调用:
在 function 内部调用 called-interactively-p 会返回 t。
如果 function 不是命令,也会直接调用而不报错。
此函数执行 command。参数 command 必须满足 commandp 谓词;
即必须是可交互式调用的函数或键盘宏。
如果 command 是字符串或向量,则用 execute-kbd-macro 执行。
如果是函数,则连同 record-flag 和 keys 参数一起传给 call-interactively(见上文)。
如果 command 是符号,则使用其函数定义。
带有 autoload 定义的符号,如果被声明代表可交互式函数,则算作命令。
这类定义会通过加载指定库并重新检查符号定义来处理。
参数 special 如果给出,表示忽略前缀参数且不清除它。 这用于执行特殊事件(see 特殊事件)。
此函数使用 completing-read(see 补全)从小缓冲读取命令名,
然后使用 command-execute 调用指定命令。
该命令的返回值即为 execute-extended-command 的返回值。
如果命令需要前缀参数,它会接收到 prefix-argument 的值。
如果 execute-extended-command 被交互式调用,
则当前原始前缀参数会被用作 prefix-argument,
并传递给所运行的任何命令。
execute-extended-command is the normal definition of M-x,
因此它使用字符串 ‘M-x ’ 作为提示。
(更好的方式是从调用 execute-extended-command 的事件中获取提示,
但实现起来较为麻烦。)
前缀参数的值(如果有)的描述也会成为提示的一部分。
(execute-extended-command 3)
---------- Buffer: Minibuffer ----------
3 M-x forward-word RET
---------- Buffer: Minibuffer ----------
⇒ t
此命令遵守 read-extended-command-predicate 变量,
该变量可过滤掉不适用于当前主模式(或已启用的次要模式)的命令。
默认情况下,该变量的值为 nil,不会过滤任何命令。
但是,将其自定义为调用函数 command-completion-default-include-p
将会执行依赖于模式的过滤。
read-extended-command-predicate 可以是任意谓词函数;
它会被传入两个参数:命令的符号和当前缓冲区。
如果该命令应在该缓冲区的补全中出现,则应返回非 nil。
此命令类似 execute-extended-command,
但会将补全提供的命令限制为与当前主模式(及已启用的次要模式)特别相关的命令。
这包括被标记为对应模式的命令(see 使用 interactive),
以及绑定到本地活跃按键映射的命令。
此命令是 M-S-x(即 “meta+shift+x”)的默认绑定。
这两个命令都会提示输入命令名,但使用不同的补全规则。 你可以在提示时使用 M-S-x 命令在这两种模式之间切换。
有时某个命令应当仅对交互式调用显示额外的视觉反馈(例如
回显区中的提示信息)。实现此需求有三种方式。检测函数是否通过
call-interactively 调用的推荐方式是:为函数添加可选参数
print-message,并通过 interactive 规范使其在交互式
调用时为非 nil 值。示例如下:
(defun foo (&optional print-message)
(interactive "p")
(when print-message
(message "foo")))
我们使用 "p" 是因为数字前缀参数永远不会是
nil。通过这种方式定义的函数,在从键盘宏中调用时也会显示该
消息。
上述使用额外参数的方法通常是最佳选择,因为它允许调用方
明确指定「将本次调用视为交互式调用」。不过你也可以通过检测
called-interactively-p 函数来实现该功能。
当调用此函数的上层函数是通过 call-interactively 调用时,
该函数返回 t。
参数 kind 应是符号 interactive 或符号 any。
若为 interactive,则仅当调用是由用户直接发起时(例如用户
按下绑定到该函数的按键序列),called-interactively-p 才返回
t——但用户运行调用该函数的键盘宏时除外(see 键盘宏)。
若 kind 为 any,则 called-interactively-p 会对任
何类型的交互式调用(包括键盘宏)返回 t。
若存在疑问,请使用 any;已知唯一适合使用
interactive 的场景是:需要决定函数运行期间是否显示帮助
信息时。
如果函数是通过 Lisp 求值(或通过 apply / funcall)
调用的,则永远不会被视为交互式调用。
以下是使用 called-interactively-p 的示例:
(defun foo ()
(interactive)
(when (called-interactively-p 'any)
(message "Interactive!")
'foo-called-interactively))
;; Type M-x foo.
⊣ Interactive!
(foo)
⇒ nil
以下示例对比了 called-interactively-p 的直接调用与间接调用:
(defun bar () (interactive) (message "%s" (list (foo) (called-interactively-p 'any))))
;; Type M-x bar.
⊣ (nil t)
编辑器命令循环会设置若干 Lisp 变量,用于记录自身及所运行命令的
状态。除 this-command 和 last-command 外,在 Lisp
程序中修改这些变量通常是不推荐的做法。
该变量记录命令循环执行的上一个命令(当前命令的前一个)的名称。 其值通常是带有函数定义的符号,但不保证一定如此。
当一个命令返回命令循环时,该变量的值会从 this-command 复制,
除非该命令为后续命令指定了前缀参数。
此变量始终是当前终端的局部变量,且不能是缓冲区局部变量。 See Multiple Terminals。
Emacs 会像设置 last-command 一样初始化该变量,
但 Lisp 程序不会修改它。
该变量存储最近执行的、不属于输入事件的命令。这是 repeat
函数会尝试重复执行的命令(See Repeating in The GNU Emacs Manual)。
该变量记录编辑器命令循环正在执行的命令名称。与 last-command
类似,其值通常是带有函数定义的符号。
命令循环会在运行命令前设置该变量,并在命令结束时将其值复制到
last-command(除非该命令为后续命令指定了前缀参数)。
部分命令会在执行期间设置该变量,作为后续运行命令的标志。
特别是文本删除类函数会将 this-command 设置为
kill-region,以便紧随其后的删除命令知晓应将新删除的文本
追加到上一次删除的内容之后。
如果不希望某个命令在出错时被识别为上一个命令,你必须在该命令中
编写相应逻辑来防止这种情况。一种方法是在命令开始时将
this-command 设置为 t,并在结束时恢复其原始值:
(defun foo (args...)
(interactive ...)
(let ((old-this-command this-command))
(setq this-command t)
...do the work...
(setq this-command old-this-command)))
我们不使用 let 绑定 this-command,因为 let
在出错时会恢复旧值 — 而这正是我们要避免的行为。
除命令重映射发生时(see 命令重映射),该变量的值与
this-command 相同。发生重映射时,this-command 表示
实际运行的命令(重映射的结果),而 this-original-command
表示原本指定要运行但被重映射为其他命令的原命令。
该变量的值与 this-command 相同,但在进入迷你缓冲区时会被递归绑定。
迷你缓冲区钩子等场景可通过该变量确定启动当前迷你缓冲区会话的命令。
该函数返回包含触发当前命令的按键序列的字符串或向量。
命令通过 read-event(无超时)读取的所有事件都会追加到末尾。
但若命令调用了 read-key-sequence,则该函数返回最后读取的按键序列
(See 读取按键序列)。如果序列中的所有事件都是可存储在字符串中的字符,
则返回值为字符串(See 输入事件)。
(this-command-keys)
;; Now use C-u C-x C-e to evaluate that.
⇒ "^X^E"
与 this-command-keys 类似,但始终以向量形式返回事件,
因此无需处理将输入事件存储在字符串中的复杂问题(see 将键盘事件存入字符串)。
该函数清空 this-command-keys 用于返回的事件表。
除非 keep-record 为非 nil,否则还会清空
recent-keys 函数后续要返回的记录(see Recording Input)。
读取密码后使用此函数非常有用,可防止密码在某些情况下作为下一个命令的一部分意外回显。
该变量保存作为按键序列一部分读取的最后一个输入事件(不计入鼠标菜单产生的事件)。
该变量的一个用途是告知 x-popup-menu 在哪里弹出菜单,
也被 y-or-n-p 内部使用(see Yes-or-No 查询)。
该变量被设置为命令循环读取的、作为命令一部分的最后一个输入事件。
该变量的主要用途是在 self-insert-command 中(用于决定插入哪个字符),
以及在 post-self-insert-hook 中(see User-Level Insertion Commands,
用于获取刚插入的字符)。
last-command-event
;; Now use C-u C-x C-e to evaluate that.
⇒ 5
值为 5 是因为这是 C-e 的 ASCII 编码。
该变量记录最后一个输入事件发往的框架。通常是事件生成时被选中的框架, 但如果该框架已将输入焦点重定向到另一框架,则值为事件被重定向到的框架。 See Input Focus。
如果最后一个事件来自键盘宏,则值为 macro。
输入事件一定有来源;有时是键盘宏、信号或
unread-command-events,但通常是来自用户操作的、连接到
计算机的物理输入设备。这些设备被称为 输入设备(input devices),Emacs 会
将每个输入事件与其来源的输入设备关联起来。它们用对每个输入
设备唯一的名称来标识。
能否确定具体使用的输入设备取决于各个系统的细节。当无法获取 该信息时,Emacs 会将键盘事件报告为来自 ‘"Virtual core keyboard"’,其他事件报告为来自 ‘"Virtual core pointer"’。(这些值在所有平台上都使用, 因为当无法获取详细设备信息时,X 服务会报告这些值。)
该变量记录最后读取的输入事件所来自的输入设备名称。
如果不存在这样的设备(即最后一个输入事件来自
unread-command-events 或来自键盘宏),则为 nil。
在 X Windows 上使用 X Input 扩展时,设备名称是一个字符串, 唯一标识连接到 X 服务的每个物理键盘、定位设备和触摸屏。 否则,根据事件是由定位设备(如鼠标)还是键盘生成, 它的值为字符串 ‘"Virtual core pointer"’ 或 ‘"Virtual core keyboard"’。
设备有多种不同类型,可以从它们的名称判断。该函数可用于判断 来自 frame 框架的事件所对应设备 name 的正确类型。
返回值是下列符号之一(“设备类别(device classes)”):
core-keyboard核心键盘;表示该设备是类键盘设备,但其他特性未知。
core-pointer核心指针;表示该设备是定位设备,但其他特性未知。
mouse计算机鼠标。
trackpoint指点杆或游戏杆(或其他类似控制装置)。
eraser绘图板手写笔的另一端,或独立橡皮擦。
pen绘图板上的笔尖、手写笔或其他类似设备。
puck外观类似鼠标,但报告相对于某个表面的绝对坐标的设备。
power-button电源按钮或音量按钮(或其他类似控制装置)。
keyboard计算机键盘。
touchscreen触摸屏。
pad通常位于绘图板周围的一组感应按钮、圆环和触控条。
touchpad间接触摸设备,如触控板。
piano电子琴等乐器。
testXTEST 扩展用于上报输入的测试设备。
当一段文本具有 display 或 composition
属性,或者是不可见文本时,可能会有多个缓冲区位置
在屏幕上显示为同一个光标位置。
因此,当命令执行完毕并返回到命令循环时,
如果光标位于这样的文本段内,命令循环通常会移动光标,
使这段文本在效果上成为不可触摸区域。
这种 光标位置调整(point adjustment) 遵循以下通用规则: 第一,调整不应改变命令的整体方向; 第二,如果命令移动了光标,调整会尽量确保光标也随之移动; 第三,Emacs 会优先选择不可触摸区域的边缘, 并在这些边缘中优先选择非粘性边缘, 从而保证新插入的文本是可见的。
命令可以通过设置变量 disable-point-adjustment
来禁止该功能:
如果命令返回到命令循环时该变量为非 nil,
则命令循环不会检查这些文本属性,
也不会将光标移出具有这些属性的文本段。
命令循环在每个命令执行前都会将该变量设为 nil,
因此如果某个命令设置了它,效果仅作用于该命令本身。
如果将该变量设为非 nil,
则将光标移出这些文本段的功能会被完全关闭。
Emacs 命令循环读取一系列 输入事件(input events), 这些事件表示键盘或鼠标操作,或是发送给 Emacs 的系统事件。 键盘操作对应的事件是字符或符号;其他事件始终是列表。 本节详细描述输入事件的表示方式与含义。
如果 object 是输入事件或事件类型,
该函数返回非 nil。
注意:任何非 nil 符号都可能被用作事件或事件类型;
eventp 无法判断某个符号是否被 Lisp 代码用作事件。
从键盘可以获取两种输入:普通按键和功能键。 普通按键对应(可能带修饰的)字符;它们产生的事件在 Lisp 中以字符表示。 字符事件(character event) 的事件类型就是字符本身(一个整数),其中可能设置了某些修饰位; 参见 事件分类。
输入字符事件由一个介于 0 到 524287 之间的 基础编码(basic code), 以及下列任意或全部 修饰位(modifier bits) 组成:
字符编码中的 2**27 位表示输入字符时按住了 Meta 键。
字符编码中的 2**26 位表示非 ASCII 控制字符。
ASCII 控制字符(如 C-a)有自己专用的基础编码, 因此 Emacs 不需要用特殊位来表示它们。 于是,C-a 的编码就是 1。
但如果你输入 ASCII 中没有的控制组合, 比如按住 Control 键再按 %, 得到的数值就是 % 的编码加上 2**26 (前提是终端支持非 ASCII 控制字符), 也就是第 27 位被置位。
字符事件编码中的 2**25 位(第 26 位)表示输入 ASCII 控制字符时按住了 Shift 键。
对于字母,基础编码本身就区分大小写; 对于数字和标点,Shift 键会选择具有不同基础编码的完全不同字符。 为了尽可能保持在 ASCII 字符集内, Emacs 对这类字符事件避免使用 2**25 位。
但是 ASCII 无法区分 C-A 和 C-a, 因此 Emacs 在 C-A 中使用 2**25 位,而在 C-a 中不使用。
字符事件编码中的 2**24 位表示输入字符时按住了 Hyper 键。
字符事件编码中的 2**23 位表示输入字符时按住了 Super 键。
字符事件编码中的 2**22 位表示输入字符时按住了 Alt 键。 (大多数键盘上标为 Alt 的按键实际上被当作 Meta 键,而非此键。)
程序中最好避免提及具体的位编号。
要检测字符的修饰位,请使用函数 event-modifiers(see 事件分类)。
使用 keymap-set 设置按键绑定时,
你可以改用类似 ‘C-H-x’ 这样的字符串来指定这些事件(表示“Control+Hyper+x”)
(see 修改按键绑定)。
大多数键盘还带有 功能键(function keys)—这些按键的名称或符号并非字符。
在 Emacs Lisp 中,功能键以符号表示;符号的名称即为功能键的标签,采用小写形式。
例如,按下标签为 F1 的按键会产生一个由符号 f1 表示的输入事件。
功能键事件的事件类型就是事件符号本身。 See 事件分类。
以下是功能键符号命名约定中的几个特殊情况:
backspace, tab, newline, return, delete这些按键对应常见的 ASCII 控制字符,大多数键盘上都设有专用按键。
在 ASCII 中,C-i 与 TAB 是同一个字符。
如果终端能够区分二者,Emacs 会将前者表示为整数 9,后者表示为符号 tab,
从而向 Lisp 程序传递这一区别。
大多数情况下,区分这两者并无实际意义。因此通常会设置
local-function-key-map(see 事件序列翻译键盘映射),
将 tab 映射为 9。于是,针对字符编码 9(即字符 C-i)的按键绑定
同样适用于 tab。该组中的其他符号也是同理。
函数 read-char 同样会将这些事件转换为字符。
在 ASCII 中,BS 实际上是 C-h。
但 backspace 会转换为字符编码 127(DEL),而非编码 8(BS)。
这符合大多数用户的习惯。
left, up, right, down光标方向键
kp-add, kp-decimal, kp-divide, …小键盘按键(位于主键盘右侧)。
kp-0, kp-1, …带数字的小键盘按键。
kp-f1, kp-f2, kp-f3, kp-f4小键盘 PF 键。
kp-home, kp-left, kp-up, kp-right, kp-down小键盘方向键。Emacs 通常会将它们转换为对应的普通按键
home、left、…
kp-prior, kp-next, kp-end, kp-begin, kp-insert, kp-delete小键盘上对其他位置常用按键的重复映射。 Emacs 通常会将它们转换为同名的普通按键。
你可以将修饰键 ALT、CTRL、HYPER、 META、SHIFT 和 SUPER 与功能键组合使用。 表示方式是在符号名称中添加前缀:
Alt 修饰键。
Ctrl 修饰键。
Hyper 修饰键。
Meta 修饰键。
Shift 修饰键。
Super 修饰键。
因此,同时按下 META 和 F3 所对应的符号为 M-f3。
当使用多个前缀时,建议按字母顺序书写;
但在按键绑定查找与修改函数的参数中,顺序并不影响结果。
Emacs 支持四种鼠标事件:点击事件、拖拽事件、 按键按下事件和移动事件。所有鼠标事件都以 列表表示。列表的 CAR 是事件类型;它表明 涉及哪个鼠标按键,以及与该按键一起使用的修饰键。 事件类型还可以区分双击或三击(see 重复事件)。 列表的其余元素提供位置和时间信息。
对于按键查找,只有事件类型是重要的:两个同类型的事件
必然会运行同一个命令。命令可以使用 ‘e’ 交互式代码
访问这些事件的完整值。
See interactive 的代码字符。
以鼠标事件开头的按键序列,是根据鼠标所在窗口的缓冲区 的按键映射读取的,而不是当前缓冲区。这并不意味着 在某个窗口中点击就会选中该窗口或其缓冲区— 这完全由该按键序列绑定的命令控制。
当用户按下鼠标按键并在同一位置释放时, 会产生一个 点击(click) 事件。根据窗口系统报告 鼠标滚轮事件的方式,转动鼠标滚轮可能产生 鼠标点击事件或鼠标滚轮事件。所有鼠标事件 都使用相同的格式:
(event-type position click-count)
这是一个符号,表示使用了哪个鼠标按键。它是
符号 mouse-1、mouse-2、… 之一,
按键从左到右编号。对于鼠标滚轮事件,它可以是
wheel-up 或 wheel-down。
你也可以使用前缀 ‘A-’、‘C-’、‘H-’、‘M-’、 ‘S-’ 和 ‘s-’ 分别表示 Alt、Control、Hyper、Meta、Shift 和 Super 修饰键,用法与功能键相同。
该符号同时也作为事件的事件类型。按键绑定通过类型
描述事件;因此,如果存在针对 mouse-1 的按键绑定,
该绑定将应用于所有 event-type 为 mouse-1 的事件。
这是一个 鼠标位置列表(mouse position list),指定鼠标事件发生的位置; 详细说明见下文。
这是同一鼠标按键到目前为止快速重复按下的次数, 或滚轮重复转动的次数。See 重复事件。
要访问鼠标事件的 position 字段中 鼠标位置列表的内容,通常应使用 访问鼠标事件 中描述的函数。
该列表的显式格式取决于事件发生的位置。 对于在文本区域、模式行、标题行、标签行、 或边栏与边缘区域中的点击,鼠标位置列表的格式为:
(window pos-or-area (x . y) timestamp object text-pos (col . row) image (dx . dy) (width . height))
这些列表元素的含义如下:
发生鼠标事件的窗口。
在文本区域中被点击的字符对应的缓冲区位置;
或者,如果事件发生在文本区域之外,则为事件发生的窗口区域。
它是符号 mode-line、
header-line、tab-line、vertical-line、
left-margin、right-margin、left-fringe 或
right-fringe 之一。
有一种特殊情况:pos-or-area 是一个包含符号 (上述符号之一)的列表,而不只是符号本身。 这种情况发生在 Emacs 注册了事件的虚拟前缀键之后。 See 读取按键序列。
事件的相对像素坐标。对于窗口文本区域中的事件,
坐标原点 (0 . 0) 取为文本区域的左上角。
See Window Sizes。对于模式行、标题行或标签行中的事件,
坐标原点是窗口本身的左上角。对于边栏、边缘区域
和垂直边框,x 没有有效数据。
对于边栏和边缘区域,y 相对于标题行的下边缘。
在所有情况下,x 和 y 坐标分别向右和向下递增。
事件发生的时间,以从系统相关的初始时间开始 计算的毫秒整数表示。
可以是 nil(表示事件发生在缓冲区文本上),
或者是格式为 (string . string-pos) 的 cons 单元
(如果事件位置存在来自文本属性或覆盖层的字符串)。
被点击的字符串,包含所有属性。
点击发生在字符串中的位置。
对于在边缘区域或边栏上的点击,这是窗口中对应行
第一个可见字符的缓冲区位置。对于在模式行、标题行
或标签行上的点击,该值为 nil。对于其他事件,
它是距离点击位置最近的缓冲区位置。
这是 x、y 位置下方字形的实际列号和行号。 如果 x 超出所在行实际文本的最后一列, col 会通过添加具有默认字符宽度的虚拟额外列来计算。 如果窗口有标题行,则第 0 行为标题行; 如果窗口还有标签行,则第 1 行为标题行; 否则为文本区域的最顶行。 对于窗口文本区域上的点击,第 0 列为文本区域的最左列; 对于模式行或标题行上的点击,则为对应区域的最左列。 对于边栏或垂直边框上的点击,这些值无有效数据。 对于边缘区域上的点击,col 从边缘区域左边缘开始计算, row 从边缘区域顶部开始计算。
如果点击位置有图像,则为 find-image 返回的图像对象
(see Defining Images);否则为 nil。
点击位置相对于距离最近的 object 字形
左上角的像素偏移。相关的 object 可以是缓冲区、
字符串或图像,见上文。如果 object 为 nil 或字符串,
坐标相对于被点击字符字形的左上角。
注意,在文本模式框架中,当 object 为 nil 时,
偏移始终为 0,因为那里每个字形都被视为恰好 1×1 像素大小。
如果点击在某个字符上(来自缓冲区文本、覆盖层或显示字符串), 则为该字符字形的像素宽度和高度;否则为被点击的 object 的尺寸。
对于在滚动条上的点击,position 具有以下格式:
(window area (portion . whole) timestamp part)
被点击滚动条所属的窗口。
该值为符号 vertical-scroll-bar。
从滚动条顶部到点击位置的像素数。
在某些工具包(包括 GTK+)中,Emacs 无法提取此数据,
因此该值始终为 0。
滚动条的总长度(以像素为单位)。
在某些工具包(包括 GTK+)中,Emacs 无法提取此数据,
因此该值始终为 0。
事件发生的时间,以毫秒为单位。
在某些工具包(包括 GTK+)中,Emacs 无法提取此数据,
因此该值始终为 0。
点击发生在滚动条的哪个部分。
它是以下符号之一:handle(滚动条滑块)、
above-handle(滑块上方区域)、
below-handle(滑块下方区域)、
up(滚动条一端的上箭头)或
down(滚动条一端的下箭头)。
对于在框架内部边框(see Frame Layout)、 框架工具栏(see 工具栏)、标签栏或菜单栏上的点击, position 具有以下格式:
(frame part (X . Y) timestamp object)
被点击的内部边框、工具栏、标签栏或菜单栏所属的框架。
被点击的框架部分。可以是以下之一:
tool-bar ¶框架有工具栏,且事件发生在工具栏区域。
tab-bar ¶框架有标签栏,且事件发生在标签栏区域。
menu-bar ¶事件发生在框架的菜单栏区域。此类点击事件 仅在纯文本框架或非工具包编译的 X 框架上发生。 (在工具包编译的 Emacs 中,菜单栏点击由工具包处理, 不会以点击事件形式暴露给 Emacs。)
left-edgetop-edgeright-edgebottom-edge点击发生在对应边框上,且距离边框最近角点 至少一个标准字符的偏移量。
top-left-cornertop-right-cornerbottom-right-cornerbottom-left-corner点击发生在内部边框的对应角点。
nil框架没有内部边框,且事件不在标签栏或工具栏上。
这通常发生在文本模式框架。
在带有内部边框的 GUI 框架上,如果框架的
drag-internal-border 参数(see Mouse Dragging Parameters)
未设置为非 nil 值,也可能出现此情况。
该成员仅在标签栏上的点击时存在, 它是包含被点击按钮信息的带属性字符串。
在 Emacs 中,你无需改变任何操作就能产生拖拽事件。 每当用户按下鼠标按键,并在释放按键前将鼠标移动到不同的字符位置时, 就会产生一个 拖拽事件(drag event)。与所有鼠标事件一样,拖拽事件在 Lisp 中以列表表示。 这些列表会同时记录鼠标的起始位置和结束位置,格式如下:
(event-type start-position end-position)
对于拖拽事件,符号 event-type 的名称包含前缀 ‘drag-’。
例如,按住鼠标按键 2 并拖动鼠标会产生 drag-mouse-2 事件。
事件的第二个和第三个元素,即上例中的 start-position 和 end-position,
会被设置为拖拽的起始和结束位置(以鼠标位置列表的形式,see 点击事件)。
你可以用同样的方式访问任何鼠标事件的第二个元素。
但是,拖拽事件可能在最初选中的框架边界之外结束。
在这种情况下,第三个元素的位置列表会使用该框架代替窗口。
‘drag-’ 前缀位于修饰键前缀(如 ‘C-’ 和 ‘M-’)之后。
如果 read-key-sequence 接收到一个没有按键绑定的拖拽事件,
而对应的点击事件存在绑定,它会将该拖拽事件转换为拖拽起始位置处的点击事件。
这意味着除非你需要,否则不必区分点击事件和拖拽事件。
点击和拖拽事件在用户释放鼠标按键时才会发生。 它们不会提前发生,因为在按键释放之前无法区分点击和拖拽。
如果你希望在按键一按下时就执行操作,就需要处理 button-down(按键按下)事件。18 这类事件在按键按下时立即发生。 它们的列表形式与点击事件完全相同(see 点击事件), 区别仅在于 event-type 符号名称包含前缀 ‘down-’。 ‘down-’ 前缀位于修饰键前缀(如 ‘C-’ 和 ‘M-’)之后。
函数 read-key-sequence 会忽略所有没有命令绑定的按键按下事件;
因此,Emacs 命令循环也会忽略它们。
这意味着除非你希望它们执行某些操作,否则无需定义按键按下事件。
定义按键按下事件的常见用途是:在按键释放前跟踪鼠标移动(通过读取移动事件)。
See 移动事件。
如果你在不移动鼠标的情况下快速连续按下同一鼠标按键多次, Emacs 会为第二次及后续的按下操作生成特殊的 重复(repeat)鼠标事件。
最常见的重复事件是 双击(double-click)事件。 当你快速点击某一按键两次时,Emacs 会产生双击事件; 该事件在你释放按键时触发(与所有点击事件的规则一致)。
双击事件的事件类型包含前缀 ‘double-’。
因此,按住 meta 键对鼠标按键 2 进行双击,
在 Lisp 程序中会表现为 M-double-mouse-2。
如果双击事件没有绑定,Emacs 会使用对应普通点击事件的绑定来执行。
因此,除非你确实需要,否则不必关注双击功能。
当用户执行双击时,Emacs 先生成一个普通点击事件,然后生成双击事件。 因此,你在设计双击事件的命令绑定时,必须假定单击命令已经运行。 它必须在单击结果的基础上,产生双击所需的效果。
如果双击的含义建立在单击含义之上,这种设计会非常方便— 这也是推荐的双击用户界面设计实践。
如果你点击一次按键,再次按下并按住拖动鼠标, 最终释放按键时会得到一个 双击拖拽(double-drag)事件。 其事件类型包含 ‘double-drag’,而非仅仅 ‘drag’。 如果双击拖拽事件没有绑定,Emacs 会寻找对应普通拖拽事件的绑定。
在双击或双击拖拽事件之前,当用户第二次按下按键时, Emacs 会生成一个 双击按下(double-down)事件。 其事件类型包含 ‘double-down’,而非仅仅 ‘down’。 如果双击按下事件没有绑定,Emacs 会寻找对应普通按键按下事件的绑定。 如果仍然找不到绑定,该双击按下事件会被忽略。
总而言之,当你点击一个按键并立即再次按下时, Emacs 会为第一次点击生成按下事件和点击事件, 在你再次按下时生成双击按下事件, 最后生成双击事件或双击拖拽事件。
如果你连续快速点击按键两次后再次按下, Emacs 会生成 三击按下(triple-down)事件, 随后是 三击(triple-click)事件或 三击拖拽(triple-drag)事件。 这些事件的类型包含 ‘triple’,而非 ‘double’。 如果任何三击事件没有绑定,Emacs 会使用对应双击事件的绑定。
如果你点击按键三次或更多次后再次按下, 超过三次的按下操作所产生的事件均为三击事件。 Emacs 不为四击、五击等事件提供单独的事件类型。 不过,你可以查看事件列表来精确获知按键被按下的次数。
该函数返回触发 event 的连续按键按下次数。 如果 event 是双击按下、双击或双击拖拽事件,返回值为 2。 如果 event 是三击事件,返回值为 3 或更大。 如果 event 是普通鼠标事件(非重复事件),返回值为 1。
要生成重复事件,连续的鼠标按键按下必须位于大致相同的屏幕位置。
double-click-fuzz 的值指定了两次连续点击之间
鼠标允许移动的最大像素数(水平或垂直),超出则不视为双击。
该变量同时也是判断鼠标移动是否算作拖拽的阈值。
要生成重复事件,连续按键按下之间的毫秒间隔必须小于 double-click-time 的值。
将 double-click-time 设置为 nil 会完全禁用多击检测。
将其设置为 t 则移除时间限制;Emacs 仅通过位置判断多击。
Emacs 有时会生成 鼠标移动(mouse motion) 事件,用于描述 鼠标在没有任何按键操作时的移动。鼠标移动事件以如下列表表示:
(mouse-movement POSITION)
position 是一个鼠标位置列表(see 点击事件), 指定鼠标光标的当前位置。与拖拽事件的结束位置一样, 该位置列表可能表示位于最初选中框架边界之外的位置, 在这种情况下,列表将使用该框架代替窗口。
track-mouse 宏会在其体内启用移动事件的生成。
在 track-mouse 体之外,Emacs 不会为单纯的鼠标移动生成事件,
这些事件也不会出现。See Mouse Tracking。
当该变量为非 nil 时,即使非常微小的移动也会生成鼠标移动事件。
否则,只要鼠标光标仍然指向文本中的同一个字形,就不会生成移动事件。
部分窗口系统支持响应用户触摸屏幕以及在触摸屏幕时移动手指的输入设备。 这些输入设备被称为触摸屏,Emacs 将它们产生的事件报告为 触摸屏事件(touchscreen events)。
触摸屏产生的大多数单个事件只有作为其他事件组成的更大序列的一部分才有意义: 例如,轻触触摸屏的简单操作涉及用户将手指放在触摸屏上并抬起, 而滑动屏幕以滚动则涉及放置手指、多次向上或向下移动手指,然后抬起手指。
对于轻触和滚动来说,由单根手指构成的简单模型已经足够, 但更复杂的手势需要支持跟踪多根手指, 其中每根手指的位置由一个 触摸点(touch point) 表示。 例如,“捏合缩放”手势可能由用户放置两根手指并分别向相反方向移动构成, 它们各自点位置之间的距离决定显示画面的缩放幅度, 而这些位置之间假想线的中心点决定缩放后显示画面的平移位置。
下面描述的底层触摸屏事件可用于实现上述所有触摸序列。 在这些事件中,每个点由一个标识该点的任意数字和一个鼠标位置列表(see 点击事件) 组成的 cons 单元表示,该列表指定事件发生时手指的位置。
(touchscreen-begin point) ¶当用户将手指按在触摸屏上创建 point 时,发送该事件。
当这些事件发生在框架或窗口的特殊部分上方时,
虚拟前缀键也会附加到这些事件与 read-key-sequence 上。
See 读取按键序列。
(touchscreen-update points) ¶当触摸屏上的某个点改变位置时,发送该事件。 points 是一个触摸点列表,包含当前触摸屏上每个触摸点的最新位置。
(touchscreen-end point canceled) ¶当 point 不再出现在显示屏上时发送该事件, 原因可能是其他程序接管了捕获,或是用户将手指从触摸屏上抬起。
如果触摸序列被其他程序(如窗口管理器)拦截,
canceled 为非 nil,此时 Emacs 应撤销或避免执行
原本由该触摸序列触发的任何编辑命令。
当这些事件发生在框架或窗口的特殊部分上方时,
虚拟前缀键也会附加到这些事件与 read-key-sequence 上。
如果触摸点按在菜单栏上,Emacs 不会生成任何对应的
touchscreen-begin 或 touchscreen-end 事件;
相反,菜单栏可能会在原本应发送 touchscreen-end 事件之后显示。
当没有命令绑定到 touchscreen-begin、
touchscreen-end 或 touchscreen-update 时,
Emacs 会调用“按键转换函数”(see 事件序列翻译键盘映射)
将包含触摸屏事件的按键序列转换为普通鼠标事件(see 鼠标事件)。
由于 Emacs 不支持区分来自不同鼠标设备的事件,
它假设在转换过程中最多有两个触摸点处于活动状态,
当超出该限制时,不保证事件转换的结果。
Emacs 采用两种不同策略将触摸事件转换为鼠标事件,
具体取决于在 touchscreen-begin 事件所在位置
处于活动状态的按键映射所绑定的命令等因素。
如果该位置有命令绑定到 down-mouse-1,
初始转换会生成一个 down-mouse-1 事件,
后续的 touchscreen-update 事件转换为鼠标移动事件(see 移动事件),
最终的 touchscreen-end 事件转换为 mouse-1
或 drag-mouse-1 事件(除非 touchscreen-end 事件
表明触摸序列已被其他程序拦截)。这被称为“简单转换”,
在触摸点移动与鼠标移动之间建立简单对应关系。
但是,某些绑定到 down-mouse-1 的命令——例如 mouse-drag-region——
要么与已定义的触摸屏手势(如“长按拖拽”)冲突,
要么不符合用户对触摸输入的预期,
不应对触摸序列进行简单转换。
如果遇到名称包含属性(see 符号属性)
ignored-mouse-command 的命令,
或者 down-mouse-1 没有绑定任何命令,
则会进行一种更特殊的转换:
此时 Emacs 会先处理触摸屏手势(see Touchscreens in The GNU Emacs Manual),
如果在结束 touchscreen-end 事件(与简单转换一样,其 canceled 参数为 nil)
之前未检测到任何手势,
且该事件位置有命令绑定到 mouse-1,
最后才尝试将触摸屏事件转换为鼠标事件。
在生成 mouse-1 事件之前,
点会被设置为 touchscreen-end 事件的位置,
并且包含该事件位置的窗口会被选中,
这是对那些假定 mouse-drag-region
已经将点设置为任意鼠标点击位置并选中发生点击窗口的包的兼容方案。
为了避免在鼠标菜单关闭后(see 菜单与鼠标)出现多余的 mouse-1 事件,
如果 down-mouse-1 绑定到一个按键映射使其成为前缀键,
Emacs 也会避免简单转换。
作为简单转换的替代,它会将结束的 touchscreen-end
转换为带有触摸序列起始位置的 down-mouse-1 事件,
从而显示鼠标菜单。
由于某些命令也绑定到 down-mouse-1 用于显示弹出菜单,
如果 down-mouse-1 绑定到名称具有 mouse-1-menu-command 属性的命令,
Emacs 会按照上一段所述的方式额外处理。
当一个触摸点已经在转换过程中,又注册了第二个触摸点时,
手势转换会终止,并测量第二个触摸点(辅助工具)
到第一个触摸点的距离。
随后这两个触摸点中任意一个的移动都会产生
touchscreen-pinch 事件,
其中包含它们新位置之间的距离与最初测量距离形成的比例,
如下表所示。
如果在转换过程中检测到触摸手势, 可能会生成以下输入事件之一:
(touchscreen-scroll window dx dy) ¶如果在转换过程中检测到 “滚动(scrolling)” 手势,
每个后续的 touchscreen-update 事件会被转换为
touchscreen-scroll 事件,
其中 dx 和 dy 以像素为单位指定
触摸点相对于启动序列的 touchscreen-begin 事件位置
或上一个 touchscreen-scroll 事件位置的相对移动,
以较晚者为准。
(touchscreen-hold posn) ¶如果在生成 touchscreen-begin 事件后,
单个活动触摸点保持静止超过 touch-screen-delay 秒,
转换过程中会检测到 “长按(long-press)” 手势,
并发送 touchscreen-hold 事件,
其中 posn 设置为包含 touchscreen-begin 事件位置的鼠标位置列表。
(touchscreen-drag posn) ¶如果在转换当前触摸序列时检测到 “长按(long-press)” 手势,
或者由于 touch-screen-extend-selection 用户选项
恢复 “拖拽选择(drag-to-select)”,
则在每个后续的 touchscreen-update 事件时发送
touchscreen-drag 事件,
其中 posn 设置为触摸点的新位置。
(touchscreen-restart-drag posn) ¶该事件在触摸序列开始时发送,
表示继续 “拖拽选择(drag-to-select)” 手势(取决于上述用户选项),
其中 posn 设置为该触摸序列中初始
touchscreen-begin 事件的位置列表。
(touchscreen-pinch posn ratio pan-x pan-y ratio-diff) ¶当辅助工具处于活动状态时, 任一活动触摸点的位置发生显著变化时发送该事件。
posn 是从辅助工具到另一个被观察触摸点连线中点的鼠标位置列表。
ratio 是被观察的两个触摸点之间的距离 除以辅助点最初注册时的距离; 也就是 “捏合(pinch)” 手势的缩放比例。
pan-x 和 pan-y 是 posn 的像素位置 与属于该系列触摸事件的上一个事件中此位置之间的差值, 如果不存在这样的事件,则为辅助工具最初注册时 两个触摸点之间的中心点。
ratio-diff 是当前事件的比例与上一个事件中 ratio 的差值; 如果不存在这样的事件,则为 ratio。
当这些事件所表示的变化幅度会导致 ratio 与上一个事件中的值相差超过 0.2 时, 或者 pan-x 与 pan-y 之和超过框架字符宽度(以像素为单位)的一半时(see Frame Font), 会发送此类事件。
为处理触摸屏事件的 Lisp 程序提供了多个函数。
下面描述的前两个函数旨在用于直接绑定到
touchscreen-begin 事件的命令;
它们允许独立于鼠标事件转换响应常用的触摸屏手势。
该函数用于跟踪源自 touchscreen-begin 事件 event 的单个 “轻触(tap)” 手势,
通常用于设置点或激活按钮。
它等待具有相同触摸标识符的 touchscreen-end 事件到达,
此时返回 t,表示手势结束。
如果在此期间到达 touchscreen-update 事件,
并且包含至少一个与 event 中标识符相同的触摸点,
则使用两个参数调用函数 update:
该 touchscreen-update 事件中的触摸点列表和 data。
如果 threshold 为非 nil,
并且此类事件表明 event 所代表的触摸点
已经超出 threshold 阈值(如果不是数字则为 10 像素)
相对于 event 位置的移动,
则返回 nil 并为该触摸点恢复鼠标事件转换,
以免妨碍识别来自其序列的任何后续触摸屏手势。
如果在此期间到达任何其他事件,返回 nil。
在这种情况下,调用者不应执行任何操作。
该函数用于跟踪源自 touchscreen-begin 事件 event 的单个“拖拽”手势。
其行为类似于 touch-screen-track-tap,
不同之处在于,如果 event 中的触摸点
没有移动足够距离(默认情况下,相对于其在 event 中的位置移动 5 像素)
以符合实际拖拽的条件,
则返回 no-drag 并避免调用 update。
除这两个函数外,还提供了一个函数, 用于绑定到通过鼠标事件转换生成的某些类型事件的命令, 以防止在调用后生成多余事件。
调用该函数后,在转换当前触摸序列期间,
会禁止在鼠标事件转换过程中生成 touchscreen-drag 事件。
它必须从绑定到 touchscreen-hold
或 touchscreen-drag 事件的命令中调用,
否则会发出错误信号。
由于该函数只能在鼠标事件转换过程中 已经识别出手势后调用, 调用后,构成前述触摸序列的触摸事件将不会生成任何鼠标事件。
本节同时讨论窗口系统和 Emacs 框架。 当仅提及 “框架(frame)” 或 “窗口(windows)” 时,指的是 Emacs 框架和 Emacs 窗口。 当提及窗口系统窗口(同时也是 Emacs 框架)时,本节始终使用 “窗口系统窗口(windwos system window)”。
窗口系统为用户提供了通用方式,以控制哪个窗口系统窗口(即 Emacs 框架)接收键盘输入。 这种对窗口系统窗口的选择称为 焦点(focus)。 当用户执行操作在 Emacs 框架之间切换时,会产生 焦点事件(focus event)。 当使用 mouse-autoselect-window 在 Emacs 框架内的窗口之间切换时,Emacs 也会产生焦点事件。
在按键序列中间产生焦点事件会打乱序列。 因此 Emacs 从不在按键序列中间产生焦点事件。 如果用户在按键序列中间(即前缀键之后)改变焦点,Emacs 会重新排列事件, 使焦点事件出现在多事件按键序列之前或之后,而不会插入其中。
全局按键映射中,用于切换框架的焦点事件的默认定义是: 按照用户预期,在 Emacs 内选中该新框架。 See Input Focus,该节点也描述了与框架焦点事件相关的钩子。 框架的焦点事件在 Lisp 中以如下列表表示:
(switch-frame new-frame)
其中 new-frame 是切换到的框架。
某些 X 窗口管理器设置为:只需将鼠标移入框架即可设置焦点。 通常,Lisp 程序无需知晓这种焦点变化,直到其他类型的输入到达。 仅当用户在新框架中实际敲击键盘按键或按下鼠标按键时,Emacs 才产生焦点事件; 仅仅在框架之间移动鼠标不会产生焦点事件。
当设置了 mouse-autoselect-window 时, 将鼠标移到框架内的新窗口上也可以切换选中窗口。 See Mouse Window Auto-selection,该节点描述了不同取值的行为。 当鼠标移到新窗口上时,会产生用于切换窗口的焦点事件。 窗口的焦点事件在 Lisp 中以如下列表表示:
(select-window new-window)
其中 new-window 是切换到的窗口。
Xwidget(see Embedded Native Widgets)可以发送事件,以向 Lisp 程序更新其状态。
这些事件称为 xwidget-event,包含描述变更性质的各种数据。
(xwidget-event kind xwidget arg) ¶每当 xwidget 中发生某种更新时,都会发送该事件。 更新有多种类型,由 kind 标识。
这是一种特殊事件(see 特殊事件), 应通过为 xwidget 添加回调函数来处理, 每当接收到针对 xwidget 的 xwidget 事件时都会调用该回调。
你可以通过设置 xwidget 属性列表中的 callback 来添加回调,
该回调应为接受 xwidget 和 kind 作为参数的函数。
load-changed ¶该 xwidget 事件表示 xwidget 已到达页面加载过程的特定阶段。 发送这些事件时,arg 包含一个字符串,进一步描述组件的状态:
download-callback ¶该事件表示某种下载已完成。
在上述事件中,arg 之后可以有更多参数: arg 本身表示下载文件的来源 URL; arg 后的第一个参数表示下载的 MIME 类型(字符串); 第二个参数包含下载文件的完整文件名。
(xwidget-display-event xwidget source) ¶每当某个 xwidget 请求显示另一个 xwidget 时,发送该事件。 xwidget 是应被显示的 xwidget, source 是请求显示 xwidget 的 xwidget。
它也是一种特殊事件,应通过回调处理。
你可以通过设置 source 属性列表中的 display-callback 来添加此类回调,
该回调应为接受 xwidget 和 source 作为参数的函数。
xwidget 的缓冲区会被设置为临时缓冲区。
显示组件时,应注意使用 set-xwidget-buffer
将缓冲区替换为将要显示该 xwidget 的缓冲区(see Embedded Native Widgets)。
还有一些其他事件类型表示系统内部发生的状况。
text-conversion ¶这类事件在系统级输入法对一个或多个缓冲区执行编辑 之后 发送。
事件发送后,输入法可能已经在多个不同框架内的多个缓冲区中做出了修改。
要确定哪些缓冲区被修改以及进行了哪些编辑,可以使用变量
text-conversion-edits,该变量在每次 text-conversion
事件发送之前被设置;它是一个如下形式的列表:
((buffer beg end ephemeral) ...)
其中 buffer 是被修改的缓冲区,beg 和 end
是在编辑完成时设置到编辑位置的标记,
而 ephemeral 可以是:一个字符串,包含插入的任何文本(或光标前被删除的文本);
t,表示该编辑是由输入法进行的临时编辑;
或 nil,表示光标之后的某些文本被删除。
是否发送此事件取决于缓冲区局部变量 text-conversion-style 的值,
该变量决定希望修改缓冲区内容的输入法将如何表现。
该变量可以取以下四个值之一:
nil表示输入法将被完全禁用,转而发送按键事件而非文本转换事件。
action表示输入法将被启用,但每当输入法想要插入新行时都会发送 RET。
password与 action 基本相同,但还会要求输入法能够插入 ASCII 字符,
并指示它不要将输入保存在无法处理敏感信息的输入法功能
(如文本建议)可能后续获取的位置。
t此值或任何其他值表示输入法将被启用,并在执行编辑后发送 text-conversion 事件。
对该变量值的修改只会在缓冲区成为框架的选中缓冲区后的下一次重绘时生效。
如果你需要立即禁用文本转换,请改用函数 set-text-conversion-style。
这有可能会在相当长的时间内锁定输入法,因此应谨慎使用。
此外,在命令循环或 read-key-sequence 读取前缀键之后,
文本转换会被自动禁用。
可以通过将变量 disable-inhibit-text-conversion
设置或绑定为非 nil 值来禁用此行为。
(delete-frame (frame)) ¶这类事件表示用户向窗口管理器发出删除某个特定窗口的命令, 而该窗口恰好是一个 Emacs 框架。
delete-frame 事件的标准定义是删除 frame。
(iconify-frame (frame)) ¶这类事件表示用户通过窗口管理器将 frame 最小化。
其标准定义为 ignore;由于框架已经被最小化,Emacs 无需执行任何操作。
设置此事件类型的目的是,如果你愿意,可以跟踪此类事件。
(make-frame-visible (frame)) ¶这类事件表示用户通过窗口管理器将 frame 恢复显示。
其标准定义为 ignore;由于框架已经可见,Emacs 无需执行任何操作。
(touch-end (position)) ¶这类事件表示用户的手指离开鼠标滚轮或触控板。 position 是一个鼠标位置列表(see 点击事件), 指定手指离开滚轮时鼠标光标的位置。
(wheel-up position clicks lines pixel-delta) ¶(wheel-down position clicks lines pixel-delta)这些事件由滚动鼠标滚轮产生。 position 是一个鼠标位置列表(see 点击事件), 指定事件发生时鼠标光标的位置。
clicks(如果存在)是滚轮快速连续滚动的次数。See 重复事件。
lines(如果存在且非 nil)是应滚动的屏幕行数(正数):
事件为 wheel-up 时向上滚动,wheel-down 时向下滚动。
pixel-delta(如果存在)是格式为 (x . y) 的 cons 单元,
其中 x 和 y 是各轴上应滚动的像素数,即 像素级增量(pixelwise deltas)。
通常两者中只有一个非零,另一个为零或接近零;
数值较大的那个轴即为窗口滚动轴。
当变量 mwheel-coalesce-scroll-events 为 nil 时,
滚动命令会忽略 lines 元素(即使非 nil),转而使用 pixel-delta 数据;
此时滚动方向由像素增量的符号决定,忽略事件类型隐含的方向(上或下)。
你可以使用这些 x 和 y 像素增量来精确判断鼠标滚轮实际移动了多少像素。
例如,像素增量可用于根据用户滚轮转动情况精确地以像素级滚动显示内容。
这种像素级滚动仅在 mwheel-coalesce-scroll-events 为 nil 时可用;
通常当该变量非 nil 时不会生成 pixel-delta 数据。
wheel-up 和 wheel-down 事件仅在某些类型的系统上生成。
在其他系统上,会改用 mouse-4 和 mouse-5 等事件。
可移植代码应同时处理 wheel-up、wheel-down 事件
以及 mwheel.el 中定义的变量 mouse-wheel-up-event
和 mouse-wheel-down-event 所指定的事件。
注意:由于历史原因,mouse-wheel-up-event 变量中保存的是
应与 wheel-down 类似处理的事件,反之亦然。
水平滚轮移动通常由 wheel-left 和 wheel-right 事件表示,
但可移植代码同样应遵循 mwheel.el 中定义的变量
mouse-wheel-left-event 和 mouse-wheel-right-event。
不过,某些鼠标在生成这些滚动事件的同时还会产生其他可能造成干扰的事件。
解决方法通常是取消绑定这些事件(例如 mouse-6 或 mouse-7),
但这高度依赖于硬件和操作系统。
(pinch position dx dy scale angle) ¶这类事件由用户在触控板上放置两根手指并相向或相离移动(“捏合(pinch)” 手势)产生。 position 是事件发生时鼠标指针位置的鼠标位置列表(see 点击事件); dx 是自同一序列中上一事件以来手指间水平距离的变化; dy 是自同一序列中上一事件以来手指的垂直移动; scale 是手指当前间距与序列开始时间距的比值; angle 是本次事件中连接手指的线段方向与同一序列中上一事件方向的角度差(以度为单位)。
由于捏合事件仅在捏合序列开始或期间发送, 它们不会报告用户在触控板上双指旋转但不捏合的手势。
position 之后的所有参数均为浮点数。
该事件通常作为序列的一部分发送:
以用户将双指放在触控板上开始,以用户抬起手指结束。
在序列的第一个事件中,dx、dy 和 angle 为 0.0;
后续事件会报告这些结构成员的非零值。
dx 和 dy 以虚拟相对单位报告,
其中 1.0 分别对应触控板的宽度和高度。
它们通常被解释为相对于手势下方对象(图像、窗口等)的大小。
(preedit-text arg) ¶当系统输入法通知 Emacs 显示某些文本以向用户提示将要插入的内容时,发送此事件。 arg 的内容取决于所使用的窗口系统。
在 X 中,arg 是一个字符串,描述要放置在光标后的文本。
它可以是 nil,表示清除之前显示的任何文本。
在 PGTK 框架中(see Frames),arg 是一个字符串列表, 包含它们的颜色和下划线属性信息,格式如下:
((string1
(ul . underline-color)
(bg . background-color)
(fg . foreground-color))
(string2
(ul . underline-color)
(bg . background-color)
(fg . foreground-color))
...
)
可以省略颜色信息,只保留字符串文本。
underline-color 可以是 t,表示使用默认下划线颜色的下划线文本;
也可以是一个字符串,即绘制下划线所用颜色的名称。
这是一个特殊事件(see 特殊事件), 通常不应由用户绑定到任何命令。 Emacs 收到后通常会在光标后的覆盖层中显示事件包含的文本。
(drag-n-drop position files) ¶当在 Emacs 外部的应用程序中选中一组文件, 然后将其拖拽并放置到 Emacs 框架上时,生成此类事件。
position 是描述事件位置的列表,格式与鼠标点击事件相同(see 点击事件); files 是被拖拽文件的文件名列表。 处理此事件的通常方式是打开这些文件。
目前此类事件仅在某些类型的系统上生成。
help-echo ¶当鼠标指针移动到具有 help-echo 文本属性的缓冲区文本部分时,生成此类事件。
生成的事件格式如下:
(help-echo frame help window object pos)
事件参数的确切含义以及使用这些参数显示帮助提示文本的方式 在 Text help-echo 中描述。
sigusr1 ¶sigusr2当 Emacs 进程收到信号 SIGUSR1 和 SIGUSR2 时生成这些事件。
它们不包含额外数据,因为信号不携带附加信息。
它们可用于调试(see 发生错误时进入调试器)。
要捕获用户信号,请在 special-event-map
中将对应的事件绑定到交互式命令(see 控制活跃按键映射表)。
该命令不带参数调用,具体的信号事件可在 last-input-event 中获取(see 事件输入的杂项功能)。
例如:
(defun sigusr-handler () (interactive) (message "Caught signal %S" last-input-event)) (keymap-set special-event-map "<sigusr1>" 'sigusr-handler)
要测试信号处理程序,可以让 Emacs 向自身发送信号:
(signal-process (emacs-pid) 'sigusr1)
language-change ¶在 MS-Windows 上,当输入语言发生变化时生成此类事件。 这通常意味着键盘按键将向 Emacs 发送来自其他语言的字符。 生成的事件格式如下:
(language-change frame codepage language-id)
其中 frame 是输入语言改变时的当前框架;
codepage 是新的代码页编号;
language-id 是新输入语言的数字 ID。
与 codepage 对应的编码系统(see Coding Systems)
是 cpcodepage 或 windows-codepage。
要将 language-id 转换为字符串(例如用于各种语言相关功能,如 set-language-environment),
可以使用 w32-get-locale-info 函数,如下所示:
;; Get the abbreviated language name, such as "ENU" for English (w32-get-locale-info language-id) ;; Get the full English name of the language, ;; such as "English (United States)" (w32-get-locale-info language-id 4097) ;; Get the full localized name of the language (w32-get-locale-info language-id t)
end-session ¶在 MS-Windows 上,当操作系统通知 Emacs 用户终止了交互会话或系统正在关机时,生成此事件。
该事件的标准定义是调用 kill-emacs 命令(see Killing Emacs),
以便有序关闭 Emacs;如果存在未保存更改,将生成自动保存文件(see 自动保存),
用户可在重启会话后使用这些文件恢复未保存的编辑。
如果这些事件中的某一个在按键序列中间到达—即在前缀键之后— 那么 Emacs 会重新排列事件顺序,使该事件出现在多事件按键序列之前或之后,而不会插入其中。
其中一些特殊事件(如 delete-frame)默认会调用 Emacs 命令;
另一些则未绑定。
如果你想安排某个特殊事件调用命令,可以通过 special-event-map 实现。
你在该映射中绑定到功能键的命令可以在 last-input-event 中查看触发它的完整事件。
See 特殊事件.
如果用户在同一位置按下并释放鼠标左键,将会生成如下的事件序列:
(down-mouse-1 (#<window 18 on NEWS> 2613 (0 . 38) -864320)) (mouse-1 (#<window 18 on NEWS> 2613 (0 . 38) -864180))
当按住控制键(Control)时,用户可能按住鼠标第二个按键,并将鼠标从一行拖动到下一行。 这会产生两个事件,如下所示:
(C-down-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219))
(C-drag-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219)
(#<window 18 on NEWS> 3510 (0 . 28) -729648))
当按住元键(Meta)和上档键(Shift)时,用户可能在窗口的模式行上按下鼠标第二个按键, 然后将鼠标拖动到另一个窗口中。这会产生如下的一对事件:
(M-S-down-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844))
(M-S-drag-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844)
(#<window 20 on carlton-sanskrit.tex> 161 (33 . 3)
-453816))
拥有输入焦点的框架可能并未占据整个屏幕,用户可能将鼠标移动到该框架的范围之外。
在 track-mouse 宏内部,这会生成如下的事件:
(mouse-movement (#<frame *ielm* 0x102849a30> nil (563 . 205) 532301936))
每个事件都有一个 事件类型(event type),该类型用于按键绑定目的对事件进行分类。 对于键盘事件,事件类型等于事件值;因此,字符的事件类型就是该字符, 功能键符号的事件类型就是符号本身。对于列表形式的事件,事件类型是列表 CAR 位置的符号。因此,事件类型始终是一个符号或一个字符。
就按键绑定而言,同一类型的两个事件是等价的;因此,它们总是执行相同的命令。 但这并不意味着它们做同样的事情,因为某些命令会查看整个事件来决定行为。 例如,某些命令会使用鼠标事件的位置来决定在缓冲区中的操作位置。
有时,更宽泛的事件分类会很有用。例如,你可能想知道某个事件是否使用了 META 键,而不管同时使用了哪个其他按键或鼠标按钮。
Emacs 提供了 event-modifiers 和 event-basic-type 函数
来方便地获取这类信息。
此函数返回 event 所带有的修饰符列表。修饰符是符号,
包括 shift、control、meta、alt、hyper
和 super。此外,鼠标事件符号的修饰符列表总会包含
click、drag、down 中的一个。
对于双击或三击事件,还会包含 double 或 triple。
参数 event 可以是完整的事件对象,也可以只是事件类型。
如果 event 是一个在当前 Emacs 会话中从未作为输入事件被读取过的符号,
那么即使 event 实际上带有修饰符,event-modifiers
也可能返回 nil。
以下是一些示例:
(event-modifiers ?a)
⇒ nil
(event-modifiers ?A)
⇒ (shift)
(event-modifiers ?\C-a)
⇒ (control)
(event-modifiers ?\C-%)
⇒ (control)
(event-modifiers ?\C-\S-a)
⇒ (control shift)
(event-modifiers 'f5)
⇒ nil
(event-modifiers 's-f5)
⇒ (super)
(event-modifiers 'M-S-f5)
⇒ (meta shift)
(event-modifiers 'mouse-1)
⇒ (click)
(event-modifiers 'down-mouse-1)
⇒ (down)
点击事件的修饰符列表会显式包含 click,但事件符号名本身
并不包含 ‘click’。类似地,ASCII 控制字符
(如 ‘C-a’)的修饰符列表包含 control,
即使通过 read-char 读取这类事件会返回已去掉控制修饰符位的数值 1。
此函数返回 event 所描述的按键或鼠标按钮,已去掉所有修饰符。
参数 event 与 event-modifiers 中的用法相同。例如:
(event-basic-type ?a)
⇒ 97
(event-basic-type ?A)
⇒ 97
(event-basic-type ?\C-a)
⇒ 97
(event-basic-type ?\C-\S-a)
⇒ 97
(event-basic-type 'f5)
⇒ f5
(event-basic-type 's-f5)
⇒ f5
(event-basic-type 'M-S-f5)
⇒ f5
(event-basic-type 'down-mouse-1)
⇒ mouse-1
本节描述用于访问鼠标按键或移动事件中数据的便捷函数。键盘事件数据也可通过
相同函数访问,但不适用于键盘事件的数据元素将返回 0 或 nil。
以下两个函数返回鼠标位置列表(see 点击事件),用于指定鼠标事件 的位置。
该函数返回 event 的起始位置。
若 event 是点击或按键按下事件,返回该事件的发生位置;若 event 是拖拽事件,返回拖拽的起始位置。
该函数返回 event 的结束位置。
若 event 是拖拽事件,返回用户释放鼠标按键的位置;若 event 是点击或按键按下事件,返回值实际为起始位置(此类事件仅包含该位置信息)。
以下函数接收鼠标位置列表作为参数,并返回其各个组成部分:
返回 position 所在的窗口。若 position 表示的位置位于触发事件 的框架之外,则返回该框架。
返回 position 中记录的窗口区域。当事件发生在窗口的文本区域时,返回
nil;否则返回一个标识事件发生区域的符号。
返回 position 对应的缓冲区位置。当事件发生在窗口的文本区域、边距区域 或边缘区域(fringe)时,返回一个表示缓冲区位置的整数;否则返回值未定义。
以 cons 单元 (x . y) 的形式返回 position
中基于像素的 x 和 y 坐标。这些坐标相对于 posn-window 返回的窗口。
以下示例展示如何将窗口文本区域中相对于窗口的坐标转换为相对于框架的坐标:
(defun frame-relative-coordinates (position)
"Return frame-relative coordinates from POSITION.
POSITION is assumed to lie in a window text area."
(let* ((x-y (posn-x-y position))
(window (posn-window position))
(edges (window-inside-pixel-edges window)))
(cons (+ (car x-y) (car edges))
(+ (cdr x-y) (cadr edges)))))
该函数返回一个 cons 单元 (col . row),包含
position 所描述的缓冲区位置对应的估算列号和行号。返回值以框架的默认
字符宽度和默认行高(含间距)为单位,由 position 对应的 x 和
y 值计算得出。(因此,若实际字符尺寸非默认值,实际行号和列号可能与
这些计算值不同。)若可选参数 use-window 为非 nil,则使用
position 所指窗口的默认字符宽度(而非框架的)进行计算。(例如,当该
窗口显示的缓冲区使用非默认缩放级别时,此参数会影响计算结果。)
注意,row 从文本区域顶部开始计数。若 position 所指窗口包含 标题行(see 窗口标题栏)或标签行,这些行**不**计入 row 计数。
以 cons 单元 (col . row) 的形式返回 position
中的实际行号和列号。返回值为 position 所指窗口中的实际行列数。
详情参见 See 点击事件。若 position 未包含实际位置值,该函数
返回 nil;此时可使用 posn-col-row 获取近似值。
注意,该函数未考虑显示字符的视觉宽度(如制表符或图片占用的视觉列数)。若需
获取规范字符单位的坐标,请改用 posn-col-row。
返回 position 所描述的字符串对象:若 position 描述缓冲区文本,
返回 nil;否则返回 cons 单元 (string . string-pos)。
返回 position 中的图片对象:若 position 位置无图片,返回
nil;否则返回图片规格 (image …)。
返回 position 所描述的图片或字符串对象:若 position 描述缓冲区
文本,返回 nil;否则返回图片 (image …) 或 cons 单元
(string . string-pos)。
以 cons 单元 (dx . dy) 的形式返回相对于
position 所描述对象左上角的、基于像素的 x 和 y 坐标。若 position
描述缓冲区文本,则返回距离该位置最近的缓冲区文本字符的相对坐标。
以 cons 单元 (width . height) 的形式返回
position 所描述对象的像素宽度和高度。若 position 描述缓冲区位置,
则返回该位置字符的尺寸。
返回 position 中的时间戳。该值为事件发生的时间(以毫秒为单位),其基准 时间点取决于所使用的窗口系统(无固定基准)。例如,在 X Window System 中,该值 表示自 X 服务器启动以来经过的毫秒数。
以下函数可根据指定的缓冲区位置或屏幕位置计算出位置列表,你可通过上文描述的 函数访问该位置列表中的数据。
该函数返回 window 中位置 pos 对应的位置列表。pos 默认值为 window 中的当前点(point);window 默认值为选中的窗口。
若 pos 未在 window 中显示,posn-at-point 返回 nil。
该函数返回指定框架/窗口 frame-or-window 中像素坐标 x 和 y
对应的位置信息,frame-or-window 默认值为选中的窗口。坐标 x 和
y 相对于选中窗口的文本区域。若可选参数 whole 为非 nil,
则 x 坐标相对于整个窗口区域(含滚动条、边距和边缘区域)。
若该变量为非 nil,鼠标位置列表的 posn-point 将被设置为“最左侧边缘
距离鼠标点击位置最近”的字形(glyph)位置,而非鼠标指针正下方的字形位置。例如,
若调用 posn-at-x-y 时 x 设为 9(该位置落在显示于第 0 列、
宽度为 10 的字符范围内),则鼠标位置列表中保存的点(point)将位于该字符 之后,
而非该字符 之前。
这些函数可用于解析滚动条事件。
该函数返回滚动条事件在滚动条内的垂直位置占比(以分数形式表示)。返回值为一个 cons 单元
(portion . whole),其中包含两个整数,二者的比值即为该分数形式的位置。
该函数实际上是将 ratio 乘以 total,并将结果四舍五入为整数。参数 ratio 并非
数值类型,而是一个序对 (num . denom)—通常是
scroll-bar-event-ratio 函数返回的值。
此函数便于将滚动条上的位置换算为缓冲区位置,具体用法如下:
(+ (point-min)
(scroll-bar-scale
(posn-x-y (event-start event))
(- (point-max) (point-min))))
需注意,滚动条事件使用两个构成比值的整数,而非一对 x、y 坐标。
在字符串的大多数使用场景中,我们将字符串理解为包含文本字符—即与缓冲区或文件中 相同类型的字符。但 Lisp 程序偶尔会使用在概念上包含键盘字符的字符串;例如,这些字符串 可能是按键序列或键盘宏定义。然而,出于历史兼容性考量,将键盘字符存储到字符串中是一个 复杂的问题,且并非总能实现。
我们建议新程序避免处理此类复杂性:不要将键盘事件存储在包含控制字符等内容的字符串中,
而是按照 key-valid-p 所识别的标准 Emacs 格式存储。
若你通过 read-key-sequence-vector(或 read-key-sequence)读取按键序列,
或通过 this-command-keys-vector(或 this-command-keys)访问按键序列,
可使用 key-description 将其转换为推荐格式。
这些复杂性源于键盘输入字符可能包含的修饰位。除 Meta 修饰符外,其余所有修饰位均无法 包含在字符串中,且仅在特殊情况下允许使用 Meta 修饰符。
最早的 GNU Emacs 版本将元字符表示为 128 至 255 范围内的编码。彼时,基础字符编码范围为
0 至 127,因此所有键盘字符编码均可存入字符串。许多 Lisp 程序在字符串常量中使用 ‘\M-’
表示元字符,尤其是在 define-key 及类似函数的参数中,且按键序列和事件序列始终
以字符串形式表示。
当我们增加对 127 以上更大基础字符编码及额外修饰位的支持时,不得不修改元字符的表示方式。 如今,用于表示字符中 Meta 修饰符的标志位为: 2**27 而此类数值无法包含在字符串中。
为支持在字符串常量中使用 ‘\M-’ 的程序,对于在字符串中包含特定元字符制定了 特殊规则。以下是将字符串解析为输入字符序列的规则:
read-key-sequence 等构造键盘输入字符字符串的函数会遵循上述规则:当事件无法存入
字符串时,会构造向量(vector)而非字符串。
当你在字符串中使用 ‘\M-’ 读取语法时,会生成 128 至 255 范围内的编码—与修改对应 键盘事件以存入字符串时得到的编码相同。因此,无论元事件以何种方式进入字符串,其在字符串中的 表现都是一致的。
不过,大多数程序最好遵循本节开头的建议,避开这些问题。
编辑器命令循环通过函数 read-key-sequence 读取按键序列,该函数内部会调用
read-event。这些事件输入相关函数也可在 Lisp 程序中直接使用。另请参见
Temporary Displays 中的 momentary-string-display,以及 等待时间流逝或输入 中的
sit-for。关于控制终端输入模式和调试终端输入的函数与变量,详见 Terminal Input。
更高层级的输入功能可参见 迷你缓冲区。
命令循环通过调用 read-key-sequence 每次读取一个按键序列。Lisp 程序也可调用此函数;
例如,describe-key 会使用它读取需要描述的按键。
该函数读取一个按键序列,并以字符串或向量形式返回。它会持续读取事件,直到收集到一个完整的 按键序列—即足以通过当前激活的按键映射表指定非前缀命令的序列。(请注意,以鼠标事件开头 的按键序列会使用鼠标所在窗口的缓冲区按键映射表读取,而非当前缓冲区的。)
若所有事件均为字符且均可存入字符串,则 read-key-sequence 返回字符串(see 将键盘事件存入字符串)。
否则返回向量,因为向量可存储各类事件—字符、符号和列表。
字符串或向量的元素即为按键序列中的事件。
读取按键序列的过程包含对事件进行多种方式的转换,See 事件序列翻译键盘映射。
参数 prompt 可为字符串(会显示在回显区作为提示),或 nil(表示不显示提示)。
参数 continue-echo 若非 nil,表示将此按键作为前一按键的延续进行回显。
默认情况下,若某个大写事件未定义绑定,但其小写等效事件已定义,则会将该事件转换为小写。
参数 dont-downcase-last 若非 nil,表示不将最后一个事件转换为小写。此参数适用于
读取待定义的按键序列场景。
参数 switch-frame-ok 若非 nil,表示若用户在输入任何内容前切换框架,则此函数应
处理 switch-frame 事件。若用户在按键序列输入过程中切换框架,或在序列起始时切换但
switch-frame-ok 为 nil,则该事件会延迟至当前按键序列读取完成后处理。
参数 command-loop 若非 nil,表示此按键序列由需要连续读取命令的程序读取。若调用方
仅读取单个按键序列,则应设为 nil。
参数 disable-text-conversion 若非 nil,表示读取此按键序列期间,系统输入法不会
直接编辑缓冲区文本;用户输入始终只会生成独立的按键事件。关于文本转换的更多信息,See 其他系统事件。
以下示例中,Emacs 会在回显区显示提示 ‘?’,随后用户按下 C-x C-f:
(read-key-sequence "?")
---------- Echo Area ----------
?C-x C-f
---------- Echo Area ----------
⇒ "^X^F"
函数 read-key-sequence 会抑制退出操作:在此函数读取输入时按下 C-g,其行为与其他
字符无异,不会设置 quit-flag。See 退出。
此函数与 read-key-sequence 功能相同,区别在于它始终以向量形式返回按键序列,
从不以字符串形式返回。See 将键盘事件存入字符串。
若输入字符为大写(或带有 Shift 修饰符)且无按键绑定,但其小写等效字符有绑定,则
read-key-sequence 会将该字符转换为小写。(可通过将用户选项
translate-upper-case-key-bindings 设置为 nil 禁用此行为。)请注意,
lookup-key 不会以这种方式执行大小写转换。
当读取输入时发生此类 Shift 转换(shift-translation),Emacs 会将变量
this-command-keys-shift-translated 设置为非 nil 值。Lisp 程序若需在被
Shift 转换后的按键调用时修改行为,可检查此变量。例如,函数 handle-shift-selection
会检查此变量的值,以确定如何激活或取消激活区域(see handle-shift-selection)。
函数 read-key-sequence 还会转换部分鼠标事件:将未绑定的拖动事件转换为点击事件,
并完全丢弃未绑定的按下按钮事件。它还会重新整理焦点事件和各类窗口事件,使其不会与其他
事件一同出现在按键序列中。
当鼠标事件或 touchscreen-begin、touchscreen-end 事件发生在窗口或框架的特殊区域
(如模式行、滚动条)时,事件类型无特殊标识—使用的符号与通常表示该鼠标按键和修饰键组合的
符号相同。关于窗口区域的信息存储在事件的其他位置—坐标中。但 read-key-sequence 会将
此信息转换为虚拟前缀按键(均为符号):tab-line、header-line、
horizontal-scroll-bar、menu-bar、tab-bar、mode-line、
vertical-line、vertical-scroll-bar、left-margin、right-margin、
left-fringe、right-fringe、right-divider 和 bottom-divider。
你可通过使用这些虚拟前缀按键定义按键序列,来为窗口特殊区域的鼠标点击定义功能。
例如,若调用 read-key-sequence 后点击窗口的模式行,会得到两个事件,如下所示:
(read-key-sequence "Click on the mode line: ")
⇒ [mode-line
(mouse-1
(#<window 6 on NEWS> mode-line
(40 . 63) 5959987))]
此变量的值为当前 Emacs 会话中已处理的按键序列总数,包括从终端读取的按键序列和执行键盘宏 时读取的按键序列。
命令输入的最低层级函数为 read-event、read-char 和 read-char-exclusive。
若需使用迷你缓冲区读取字符,可使用 read-char-from-minibuffer(see 提出多选问题)。
该函数读取并返回下一个命令输入事件,必要时会等待直至有事件可用。
返回的事件可能直接来自用户,也可能来自键盘宏。它不会经过键盘输入编码系统解码(详见 see Terminal I/O Encoding)。
若可选参数 prompt 非 nil,则应为字符串,会显示在回显区作为提示。若 prompt 为
nil 或字符串 ‘""’,read-event 不会显示任何提示信息表明正在等待输入;
而是通过回显方式提示:显示导致当前命令执行或被当前命令读取的事件描述。See The Echo Area。
若 inherit-input-method 非 nil,则会启用当前输入法(若有),允许输入非
ASCII 字符。否则,读取此事件时禁用输入法处理。
若 cursor-in-echo-area 非 nil,则 read-event 会将光标临时移至回显区,
置于已显示消息的末尾。否则 read-event 不会移动光标。
若 seconds 非 nil,则应为数字,指定等待输入的最长时间(以秒为单位)。若在该时间内
无输入到达,read-event 会停止等待并返回 nil。浮点数类型的 seconds 表示等待
小数秒数。部分系统仅支持整数秒数,此类系统会将 seconds 向下取整。若 seconds 为
nil,read-event 会一直等待直至有输入到达。
若 seconds 为 nil,则 Emacs 在等待用户输入期间会被视为空闲状态。空闲计时器——即
通过 run-with-idle-timer 创建的计时器(see Idle Timers)——可在此期间运行。
但如果 seconds 非 nil,则空闲状态保持不变:若调用 read-event 时 Emacs 处于
非空闲状态,则在 read-event 执行期间始终保持非空闲;若 Emacs 处于空闲状态(例如调用发生
在空闲计时器内部),则始终保持空闲。
若 read-event 接收到被定义为帮助字符的事件,则在某些情况下会直接处理该事件而不返回。
See 帮助函数。某些其他事件(称为 特殊事件(special events))也会在 read-event 内部
直接处理(see 特殊事件)。
以下示例展示调用 read-event 后按下右箭头功能键的结果:
(read-event)
⇒ right
该函数读取并返回一个字符输入事件。若用户生成的事件非字符(如鼠标点击或功能键事件),
read-char 会抛出错误。参数用法与 read-event 相同。
若事件带有修饰符,Emacs 会尝试解析并返回对应字符的编码。例如,用户按下 C-a 时,函数返回 1,
即 ‘C-a’ 字符的 ASCII 编码。若部分修饰符无法体现在字符编码中,read-char 会
在返回的事件中保留未解析的修饰位。例如,用户按下 C-M-a 时,函数返回 134217729(十六进制
为 8000001)——即带有 Meta 修饰位的 ‘C-a’。此值并非有效的字符编码:无法通过
characterp 测试(see Character Codes)。可使用 event-basic-type
(see 事件分类)提取去除修饰位后的字符编码;使用 event-modifiers
测试 read-char 返回的字符事件中的修饰符。
以下第一个示例中,用户按下字符 1(ASCII 编码 49)。第二个示例展示一个键盘宏定义,
该宏通过 eval-expression 从迷你缓冲区调用 read-char。read-char 读取键盘宏
的下一个字符(即 1),随后 eval-expression 在回显区显示其返回值。
(read-char)
⇒ 49
;; 假设此处使用 M-: 执行这段代码。
(symbol-function 'foo)
⇒ "^[:(read-char)^M1"
(execute-kbd-macro 'foo)
⊣ 49
⇒ nil
该函数读取并返回一个字符输入事件。若用户生成的事件非字符事件,read-char-exclusive 会
忽略该事件并继续读取下一个事件,直至获取到字符。参数用法与 read-event 相同。返回值可能
包含修饰位,与 read-char 一致。
上述函数均不抑制退出操作。
此变量存储从终端接收的输入事件总数——不计入键盘宏生成的事件。
需要强调的是,与 read-key-sequence 不同,read-event、read-char 和
read-char-exclusive 不会执行 事件序列翻译键盘映射 中描述的转换操作。若你希望读取
单个按键并考虑这些转换(例如,在终端中读取 功能键,或从 xterm-mouse-mode
读取 鼠标事件),可使用函数 read-key:
该函数读取单个按键。它介于 read-key-sequence 和 read-event 之间:与前者不同,
它仅读取单个按键而非按键序列;与后者不同,它不会返回原始事件,而是根据
input-decode-map、local-function-key-map 和 key-translation-map
(see 事件序列翻译键盘映射)对用户输入进行解码和转换。
参数 prompt 可为字符串(会显示在回显区作为提示),或 nil(表示不显示提示)。
若参数 disable-fallbacks 非 nil,则不应用 read-key-sequence 中针对未绑定
按键的常规回退逻辑。这意味着不会丢弃鼠标按下按钮事件和多点击事件,且不会应用
local-function-key-map 和 key-translation-map。若为 nil 或未指定,
仅禁用最后一个事件的小写转换这一回退逻辑。
该函数使用 read-from-minibuffer 读取并返回 chars 中的单个字符(chars 应为
单个字符组成的列表)。它会丢弃所有非 chars 成员的输入字符,并显示相应提示信息。
可选参数 inhibit-quit 默认被忽略,但如果变量 read-char-choice-use-read-key 非
nil,此函数会使用 read-key 而非 read-from-minibuffer,此时若
inhibit-quit 非 nil,表示在等待有效输入期间忽略键盘退出事件。此外,若
read-char-choice-use-read-key 非 nil,调用此函数时将 help-form
(see 帮助函数)绑定为非 nil 值,会在用户按下 help-char 时计算
help-form 并显示结果;随后继续等待有效输入字符或键盘退出事件。
向用户提出一道多项选择题。prompt 应为字符串,作为提示显示。
choices 为关联列表(alist),每个条目包含:第一个元素为需输入的字符,第二个元素为提示时 显示的条目短名称(若空间不足可能被缩短),第三个可选元素为详细说明(用户请求更多帮助时会 显示在帮助缓冲区中)。
若可选参数 help-string 非 nil,则应为字符串,包含所有选项的详细描述。用户按下
? 时,会在帮助缓冲区显示此字符串,而非默认自动生成的描述。
若可选参数 show-help 非 nil,则会立即显示帮助缓冲区(在用户输入前)。若为字符串,
则将其用作帮助缓冲区的名称。
若可选参数 long-form 非 nil,用户需输入长格式答案(使用 completing-read),
而非按下单个按键。答案必须是 choices 列表中条目的第二个元素。
返回值为 choices 中匹配的条目。
(read-multiple-choice "Continue connecting?" '((?a "always" "Accept certificate for this and future sessions.") (?s "session only" "Accept certificate this session only.") (?n "no" "Refuse to use certificate, close connection.")))
在图形终端中,read-multiple-choice-face 面(face)用于高亮名称字符串中的匹配字符。
Emacs 在从 read-event 返回事件之前,会先根据 extra-keyboard-modifiers
修改它读取的每个事件,然后通过 keyboard-translate-table 进行转换(如适用)。
该变量允许 Lisp 程序在键盘上“虚拟按下”修饰键。其值是一个字符,只有字符的修饰位有效。
每当用户按下一个键盘按键时,该按键会被修改,如同那些修饰键被按住一样。
例如,如果你将 extra-keyboard-modifiers 绑定为 ?\C-\M-a,
那么在该绑定作用域内输入的所有键盘字符都会被附加 Control 和 Meta 修饰。
字符 ?\C-@(等价于整数 0)在此处不算作控制字符,而是视为不带任何修饰的字符。
因此,将 extra-keyboard-modifiers 设置为 0 会取消所有修饰。
在窗口系统下,程序可以通过这种方式虚拟按下任意修饰键。 否则,只能虚拟按下 CTL 和 META 键。
注意,该变量仅对真正来自键盘的事件生效,对鼠标事件或其他任何事件没有影响。
这个终端局部变量是键盘字符的转换表。它允许你在不修改任何命令绑定的情况下重新映射键盘按键。
其值通常是一个字符表(char-table),否则为 nil。
(它也可以是字符串或向量,但这已被视为过时用法。)
如果 keyboard-translate-table 是一个字符表(see 字符表),
那么从键盘读取的每个字符都会在此字符表中查找。
如果查找到的值非 nil,则使用该值代替实际输入的字符。
注意,这种转换是字符从终端读取后发生的第一件事。
像 recent-keys 和日志文件这类记录功能会保存转换之后的字符。
还要注意,该转换发生在字符被交给输入法处理之前(see Input Methods)。
如果你希望在输入法处理之后再转换字符,请使用 translation-table-for-input
(详见 see Translation of Characters)。
该函数修改 keyboard-translate-table,将字符编码 from 转换为字符编码 to。
如有必要,它会创建键盘转换表。from 和 to 都应该是满足 key-valid-p
的字符串(see 按键序列)。如果 to 为 nil,
该函数会删除 from 已有的任何转换。
下面是一个使用 keyboard-translate-table 让 C-x、C-c 和 C-v
执行剪切、复制和粘贴操作的示例:
(key-translate "C-x" "<control-x>") (key-translate "C-c" "<control-c>") (key-translate "C-v" "<control-v>") (keymap-global-set "<control-x>" 'kill-region) (keymap-global-set "<control-c>" 'kill-ring-save) (keymap-global-set "<control-v>" 'yank)
在支持扩展 ASCII 输入的图形终端上,你仍然可以通过按住 Shift 键来输入这些字符, 以获得它们标准的 Emacs 含义。就键盘转换而言,这样得到的是不同的字符, 但通常具有相同的原有含义。
关于在 read-key-sequence 层面转换事件序列的机制,see 事件序列翻译键盘映射。
如果你需要转换非字符的输入事件(即对其调用 characterp 返回 nil),
必须使用那里描述的事件转换机制。
事件读取函数会调用当前输入法(如果有)(see Input Methods)。
如果 input-method-function 的值非 nil,它应当是一个函数;
当 read-event 读取到不带任何修饰位的可打印字符(包括 SPC)时,
会调用该函数,并将该字符作为参数传入。
如果该变量非 nil,其值指定当前输入法函数。
警告: 不要使用 let 绑定此变量。它通常是缓冲区局部的,
如果你在读取输入时绑定它(这也正是你 会 去绑定它的时机),
那么当 Emacs 处于等待状态时异步切换缓冲区,会导致该变量的值在错误的缓冲区中被恢复。
输入法函数应当返回一个事件列表,这些事件将被用作输入。
(如果列表为 nil,表示没有输入,因此 read-event 会等待下一个事件。)
这些事件会在 unread-command-events 中的事件之前被处理(see 事件输入的杂项功能)。
由输入法函数返回的事件不会再次被传给输入法函数,即使它们是不带修饰位的可打印字符。
如果输入法函数调用了 read-event 或 read-key-sequence,
它应当先将 input-method-function 绑定为 nil,以避免递归。
读取按键序列的第二个及后续事件时,不会调用输入法函数。
因此,这些字符不会经过输入法处理。
输入法函数应当检查 overriding-local-map 和
overriding-terminal-local-map 的值;
如果其中任一变量非 nil,输入法应将其参数放入列表并直接返回该列表,不再做其他处理。
你可以使用函数 read-quoted-char 要求用户指定一个字符,
并允许用户方便地指定控制字符或元字符,既可以直接输入,也可以用八进制字符码输入。
命令 quoted-insert 使用此函数。
该函数类似于 read-char,区别在于:如果读取的第一个字符是八进制数字(0–7),
它会继续读取任意数量的八进制数字(遇到非八进制数字时停止),
并返回该数字字符码所代表的字符。
如果终止八进制序列的字符是 RET,该字符会被忽略。
其他任何终止字符会在此函数返回后继续作为输入使用。
读取第一个字符时会抑制退出操作,以便用户可以输入 C-g。See 退出。
如果提供了 prompt,它指定用于提示用户的字符串。 提示字符串总是显示在回显区,后面紧跟一个 ‘-’。
下面的例子中,用户输入八进制数 177(十进制为 127)。
(read-quoted-char "What character")
---------- Echo Area ----------
What character 1 7 7-
---------- Echo Area ----------
⇒ 127
本节介绍如何预读事件而不消耗它们、如何检查待处理输入,以及如何丢弃待处理输入。
另请参见函数 read-passwd(see 读取密码)。
该变量存储等待作为命令输入被读取的事件列表。事件按其在列表中的顺序被使用, 且在使用时逐个从列表中移除。
该变量的存在是因为某些情况下,函数读取一个事件后可能决定不使用它。 将事件存入此变量后,命令循环或读取命令输入的函数会正常处理该事件。
例如,实现数字前缀参数的函数会读取任意数量的数字字符。当它遇到非数字事件时, 必须将该事件回退(unread),以便命令循环能够正常读取它。 同样,增量搜索功能会使用此特性来回退那些在搜索中无特殊含义的事件, 因为这些事件应当退出搜索并正常执行。
从按键序列中提取事件并放入 unread-command-events 的可靠且简便的方法,
是使用 listify-key-sequence(见下文)。
通常你需要将事件添加到该列表的头部,这样最近回退的事件会被优先重新读取。
从该列表中读取的事件,通常不会被添加到当前命令的按键序列中(例如 this-command-keys
的返回值),因为这些事件在首次被读取时已经被添加过一次。
形式为 (t . event) 的元素会强制将 event 添加到当前命令的按键序列中。
从该列表中读取的元素,通常会被记录功能(see Recording Input)
和键盘宏定义过程(see 键盘宏)所记录。
但形式为 (no-record . event) 的元素,会让 event 被正常处理但不被记录。
该函数将字符串或向量类型的 key 转换为单个事件组成的列表,
你可以将此列表放入 unread-command-events 中。
该函数判断当前是否有可读取的命令输入。它会立即返回:
若有可用输入则返回 t,否则返回 nil。
极少数情况下,即使无可用输入,它也可能返回 t。
若可选参数 check-timers 非 nil,则当无可用输入时,Emacs 会运行所有就绪的计时器。
See Timers for Delayed Execution。
该变量记录最后一个从终端读取的输入事件,无论该事件是作为命令的一部分读取, 还是由 Lisp 程序显式读取。
在以下示例中,Lisp 程序读取字符 1(ASCII 编码 49),
该值会成为 last-input-event 的值;
而 C-e(假设使用 C-x C-e 命令执行该表达式)仍为 last-command-event 的值。
(progn (print (read-char))
(print last-command-event)
last-input-event)
⊣ 49
⊣ 5
⇒ 49
该结构执行 body 中的表达式,并返回最后一个表达式的值——但仅在无输入到达时生效。
若在执行 body 表达式期间有任何输入到达,会终止这些表达式的执行(行为与退出操作类似)。
如果被真正的退出操作中止,while-no-input 返回 nil;
如果被其他输入的到达中止,则返回 t。
若 body 中的某部分将 inhibit-quit 绑定为非 nil,
则在该部分执行期间到达的输入,要等到该部分执行结束后才会触发中止。
如果你希望能够区分 body 计算出的所有可能值与两种中止情况, 可以按如下方式编写代码:
(while-no-input
(list
(progn . body)))
该函数丢弃终端输入缓冲区中的所有内容,并取消任何可能正在定义过程中的键盘宏。
它返回 nil。
在以下示例中,用户可能在开始执行该表达式后立即输入多个字符。
当 sleep-for 休眠结束后,discard-input 会丢弃休眠期间输入的所有字符。
(progn (sleep-for 2)
(discard-input))
⇒ nil
某些 特殊事件(special events) 会在极低层级被处理——一旦被读取就立即处理。
read-event 函数会自行处理这些事件,永远不会将它们返回。
相反,它会持续等待第一个非特殊事件,并返回该事件。
特殊事件不会回显,不会被组合成按键序列,也不会出现在 last-command-event
或 (this-command-keys) 的值中。它们不会丢弃数值参数,不能通过
unread-command-events 回退,不能出现在键盘宏中,在定义键盘宏时也不会被记录。
但是,特殊事件在被读取后会立即出现在 last-input-event 中,
事件的处理函数可以通过该变量获取实际的事件。
事件类型 iconify-frame、make-frame-visible、delete-frame、
drag-n-drop、language-change 以及用户信号如 sigusr1
通常都以这种方式处理。
用于定义如何处理特殊事件(以及哪些事件是特殊事件)的按键映射表存放在变量
special-event-map 中(see 控制活跃按键映射表)。
等待函数用于等待指定时长,或等待输入到来。例如,你可能希望在计算过程中暂停,
让用户有时间查看显示内容。sit-for 会暂停并刷新屏幕,有输入时立即返回;
而 sleep-for 只会暂停,不刷新屏幕。
该函数执行刷新显示(前提是没有来自用户的待处理输入),然后等待 seconds 秒,
或直到有输入可用。sit-for 的通常用途是让用户有时间阅读你显示的文本。
如果 sit-for 完整等待了指定时间且没有输入到达,则返回 t
(see 事件输入的杂项功能)。否则返回 nil。
参数 seconds 不必是整数。如果是浮点数,sit-for 会等待小数秒。
部分系统只支持整数秒,在这些系统上 seconds 会向下取整。
表达式 (sit-for 0) 等价于 (redisplay),
即在没有待处理输入时,立即请求刷新显示,无延迟。
See Forcing Redisplay。
如果 nodisp 非 nil,则 sit-for 不刷新显示,
但仍会在有输入(或超时)时立即返回。
在批处理模式下(详见 see Batch Mode),sit-for 无法被中断,
即使是来自标准输入描述符的输入也不行。此时它等价于下面介绍的 sleep-for。
该函数仅暂停 seconds 秒,不刷新显示,也不关注是否有输入可用。返回 nil。
参数 seconds 不必是整数。如果是浮点数,sleep-for 会等待小数秒。
也可以用两个参数调用 sleep-for,即 (sleep-for seconds millisec),
但这已被视为过时用法,未来会被移除。
当你需要确保产生一段延迟时,使用 sleep-for。
用于获取当前时间的函数,See Time of Day。
在 Lisp 函数运行时键入 C-g 会使 Emacs 退出(quit) 当前正在执行的任何操作。这意味着控制权会返回到 最内层的活动命令循环。
在命令循环等待键盘输入时键入 C-g 不会触发退出;它会作为普通输入字符处理。
在最简单的情况下,你无法区分二者的差异,因为 C-g
通常会运行 keyboard-quit 命令,其作用就是退出。
但当 C-g 跟在前缀键之后时,二者会组合成一个未定义的按键。
其效果是取消前缀键以及任何前缀参数。
在迷你缓冲区中,C-g 有不同的定义:它会中止迷你缓冲区操作。 实际上,这意味着它会退出迷你缓冲区,然后执行退出操作。 (单纯的退出只会返回到迷你缓冲区 内部 的命令循环。) 命令读取器在读取输入时 C-g 不直接触发退出的原因, 是为了能以这种方式在迷你缓冲区中重新定义它的含义。 迷你缓冲区中不会重新定义跟在前缀键后的 C-g, 它仍会执行取消前缀键和前缀参数的常规操作。 如果 C-g 总是直接触发退出,这一行为也无法实现。
当 C-g 直接触发退出时,其原理是将变量
quit-flag 设置为 t。Emacs 会在合适的时机检查该变量,
若其值非 nil 则执行退出操作。因此,无论以何种方式将
quit-flag 设置为非 nil 值,都会触发退出。
在 C 代码层面,退出操作并非在任意位置都能触发;仅会在
检查 quit-flag 的特殊位置触发。这样设计的原因是,
在其他位置退出可能导致 Emacs 内部状态出现不一致。
由于退出操作会延迟到安全位置才执行,因此退出不会导致 Emacs 崩溃。
某些函数(如 read-key-sequence 或
read-quoted-char)即使在等待输入时,也会完全阻止退出操作。
此时 C-g 不会触发退出,而是作为请求的输入。
对于 read-key-sequence,这一设计是为了实现
命令循环中 C-g 的特殊行为。对于 read-quoted-char,
这一设计则是为了让 C-q 能够引用 C-g。
你可以通过将变量 inhibit-quit 绑定为非 nil 值,
来阻止 Lisp 函数某一部分执行退出操作。此时,
尽管 C-g 仍会照常将 quit-flag 设置为 t,
但会阻止其常规结果—退出操作的执行。
最终,inhibit-quit 会恢复为 nil(例如在
let 形式结束时,其绑定被解除)。若此时
quit-flag 仍为非 nil,则会立即执行请求的退出操作。
当你希望确保程序的关键段不会触发退出时,这种行为非常理想。
在部分函数(如 read-quoted-char)中,C-g
会以不涉及退出的特殊方式处理。实现方式是:在绑定
inhibit-quit 为 t 的状态下读取输入,
并在 inhibit-quit 恢复为 nil 之前将
quit-flag 设置为 nil。以下是
read-quoted-char 定义的节选,展示了具体实现方式;
同时也表明,输入第一个字符后允许执行常规退出操作。
(defun read-quoted-char (&optional prompt)
"...documentation..."
(let ((message-log-max nil) done (first t) (code 0) char)
(while (not done)
(let ((inhibit-quit first)
...)
(and prompt (message "%s-" prompt))
(setq char (read-event))
(if inhibit-quit (setq quit-flag nil)))
...set the variable code...)
code))
若该变量值非 nil,则 Emacs 会立即执行退出操作(除非
inhibit-quit 为非 nil)。无论
inhibit-quit 取值如何,键入 C-g 通常都会将
quit-flag 设置为非 nil。
该变量决定了当 quit-flag 被设置为非 nil 值时,
Emacs 是否应执行退出操作。若 inhibit-quit 为
非 nil,则 quit-flag 不会产生任何特殊效果。
该宏会依次执行 body 形式,但即便在该结构外部
inhibit-quit 为非 nil,也允许在
body 内部(至少本地)执行退出操作。它会返回
body 中最后一个形式的值;若因退出而终止执行,则返回
nil。
若进入 with-local-quit 时 inhibit-quit 为
nil,则仅执行 body,且设置 quit-flag 会触发
常规退出。但如果 inhibit-quit 为非 nil(导致常规退出被延迟),
非 nil 的 quit-flag 会触发一种特殊的本地退出。
这会终止 body 的执行,并在 quit-flag 仍为非
nil 的状态下退出 with-local-quit 体,
因此一旦允许,就会立即执行另一次(常规)退出。
若在 body 开始时 quit-flag 已为非 nil,
则会立即触发本地退出,且完全不执行体内容。
该宏主要适用于从定时器、进程过滤器、进程哨兵、
pre-command-hook、post-command-hook
以及其他 inhibit-quit 通常被绑定为 t 的位置调用的函数。
若希望退出但不中止键盘宏的定义或执行,你可以触发
minibuffer-quit 条件。其效果与 quit 条件几乎完全相同,
区别在于命令循环中的错误处理会处理该条件,且不会退出键盘宏的定义或执行。
你可以指定除 C-g 之外的其他字符作为退出键。
参见 Input Modes 中的 set-input-mode 函数。
大多数 Emacs 命令均可使用 前缀参数(prefix argument),即在命令执行前
指定的一个数值。(请勿将前缀参数与前缀键混淆。)前缀参数
始终由一个值表示,该值可以是 nil,表示当前无
前缀参数。每个命令可选择使用或忽略前缀参数。
前缀参数有两种表示形式:原始(raw) 形式与 数字(numeric) 形式。编辑器命令循环内部使用原始形式, 存储该信息的 Lisp 变量同样如此,但命令可请求 使用任意一种形式。
原始前缀参数的可能取值如下:
nil,表示无前缀参数。其数字值为 1,
但许多命令会区分 nil 与整数 1。
-。表示键入了 M-- 或 C-u -
且未跟随数字。等效数字值为 −1,
但部分命令会区分整数 −1 与符号 -。
我们通过对下述函数使用不同前缀调用, 演示这些取值情况:
(defun display-prefix (arg) "Display the value of the raw prefix arg." (interactive "P") (message "%s" arg))
以下为使用不同原始前缀参数调用 display-prefix 的结果:
M-x display-prefix ⊣ nil C-u M-x display-prefix ⊣ (4) C-u C-u M-x display-prefix ⊣ (16) C-u 3 M-x display-prefix ⊣ 3 M-3 M-x display-prefix ⊣ 3 ; (Same asC-u 3.) C-u - M-x display-prefix ⊣ - M-- M-x display-prefix ⊣ - ; (Same asC-u -.) C-u - 7 M-x display-prefix ⊣ -7 M-- 7 M-x display-prefix ⊣ -7 ; (Same asC-u -7.)
Emacs 使用两个变量存储前缀参数:
prefix-arg 与 current-prefix-arg。
诸如 universal-argument 这类为其他命令
设置前缀参数的命令,会将参数存入 prefix-arg。
与之相对,current-prefix-arg 用于将前缀参数
传递给当前命令,因此修改它不会影响后续命令的前缀参数。
通常,命令会在 interactive 声明中
指定使用数字形式还是原始形式的前缀参数。
(参见 使用 interactive。)函数也可直接
通过变量 current-prefix-arg 查看前缀参数,
但这种方式不够规范。
该函数返回合法原始前缀参数 arg 对应的数字含义。
参数可为符号、数字或列表。若为 nil,返回 1;
若为 -,返回 −1;若为数字,返回该数字;
若为列表,返回列表的 CAR(应为数字)。
该变量保存 当前 命令的原始前缀参数。
命令可直接检查它,但常规获取方式为
(interactive "P")。
该变量的值为 下一条 编辑命令的原始前缀参数。
诸如 universal-argument 这类为后续命令
指定前缀参数的命令,通过设置该变量工作。
上一条命令所使用的原始前缀参数值。
下列命令用于为后续命令设置前缀参数。 请勿出于其他目的调用它们。
该命令读取输入并为后续命令指定前缀参数。 除非你明确操作目的,否则请勿自行调用该命令。
该命令为后续命令追加前缀参数。参数 arg 为该命令执行前已有的原始前缀参数,用于计算 更新后的前缀参数。除非你明确操作目的, 否则请勿自行调用该命令。
该命令为下一条命令添加数字参数。参数 arg 为该命令执行前已有的原始前缀参数, 其值取反后形成新的前缀参数。除非你明确 操作目的,否则请勿自行调用该命令。
Emacs 启动时会自动进入命令循环。 这一顶层命令循环调用永不退出;只要 Emacs 运行, 它就会持续运行。Lisp 程序也可调用命令循环。 由于这会导致命令循环被多次激活,我们称之为 递归编辑(recursive editing)。递归编辑层级的作用是挂起调用它的 任意命令,并允许用户在恢复该命令前执行任意编辑操作。
递归编辑期间可用的命令与顶层编辑循环中 可用的命令相同,且均在按键映射中定义。 仅有少数特殊命令能退出递归编辑层级; 其他命令执行完毕后会返回递归编辑层级。 (退出用的特殊命令始终可用,但无递归编辑 进行时它们不执行任何操作。)
所有命令循环(包括递归循环)均会设置通用错误 处理程序,因此命令循环中运行的命令若出错, 不会导致循环退出。
迷你缓冲区输入是一种特殊的递归编辑。 它有一些特殊处理,例如启用迷你缓冲区和 迷你缓冲区窗口的显示,但数量比你预想的少。 部分按键在迷你缓冲区中的行为不同,但这仅因 迷你缓冲区的本地映射;若切换窗口,仍会获得 常规的 Emacs 命令。
调用 recursive-edit 函数可进入递归编辑层级。
该函数包含命令循环;同时会调用带 exit 标签的
catch,因此可通过向 exit 抛出值
退出递归编辑层级(see 显式非局部退出:catch 和 throw)。
抛出 t 值会使 recursive-edit 退出,
控制权返回上一层命令循环。这一操作称为
中止(aborting),可通过 C-](abort-recursive-edit)
完成。类似地,抛出字符串值会使 recursive-edit
触发错误,并打印该字符串作为提示信息。
若抛出函数,recursive-edit 会在返回前无参调用该函数。
抛出其他任意值会使 recursive-edit 正常返回至
调用它的函数。命令 C-M-c(exit-recursive-edit)
即实现此功能。
除使用迷你缓冲区的场景外,大多数应用不应使用 递归编辑。通常,临时将当前缓冲区的主模式切换为 专用主模式(并定义返回原模式的命令)会更便于用户操作。 (Rmail 中的 e 命令即采用此技术。) 或者,若需让用户递归编辑不同文本,可创建并选中 一个专用模式的新缓冲区。在该模式中定义完成处理 并返回原缓冲区的命令。(Rmail 中的 m 命令 即采用此方式。)
递归编辑在调试中十分有用。你可在函数定义中插入
debug 调用作为断点,以便函数执行到此处时
查看运行环境。debug 会调用递归编辑,
同时提供调试器的其他功能。
递归编辑层级也用于 query-replace 中键入
C-r 或使用 C-x q(kbd-macro-query)时。
该函数调用编辑器命令循环。Emacs 初始化时会自动 调用它,让用户开始编辑。从 Lisp 程序中调用时, 它会进入递归编辑层级。
若当前缓冲区与选中窗口的缓冲区不同,
recursive-edit 会保存并恢复当前缓冲区。
否则,若切换缓冲区,recursive-edit 返回后,
切换后的缓冲区将成为当前缓冲区。
以下示例中,函数 simple-rec 先将光标前移一个单词,
再进入递归编辑,并在回显区打印提示信息。
用户可执行任意编辑操作,然后键入 C-M-c
退出并继续执行 simple-rec。
(defun simple-rec ()
(forward-word 1)
(message "Recursive edit in progress")
(recursive-edit)
(forward-word 1))
⇒ simple-rec
(simple-rec)
⇒ nil
该函数退出最内层的递归编辑(包括迷你缓冲区输入)。
其实现等效于 (throw 'exit nil)。
该函数在退出递归编辑后触发 quit,从而中止
请求最内层递归编辑的命令(包括迷你缓冲区输入)。
其实现等效于 (throw 'exit t)。
See 退出。
该函数退出所有递归编辑层级;它无返回值, 会直接跳出所有计算过程,返回至主命令循环。
该函数返回当前递归编辑的深度。无递归编辑激活时, 返回 0。
禁用命令(Disabling a command)是将该命令标记为执行前需要 用户确认。禁用机制用于对新手可能造成困扰 的命令,防止其误操作使用。
禁用命令的底层机制是为该命令对应的 Lisp 符号
设置一个非 nil 的 disabled 属性。
这些属性通常由用户的初始化文件
(see The Init File)通过如下 Lisp 表达式设置:
(put 'upcase-region 'disabled t)
部分命令默认带有该属性(如需可在初始化文件中移除)。
若 disabled 属性的值为字符串,
提示命令被禁用的信息会包含该字符串。例如:
(put 'delete-region 'disabled
"Text deleted this way cannot be yanked back!\n")
关于调用被禁用命令时的具体行为, 参见 See Disabling in The GNU Emacs Manual。 禁用命令对从 Lisp 程序中以函数形式调用该命令无影响。
disabled 属性的值也可以是一个列表,
其首个元素为符号 query。这种情况下会询问
用户是否执行该命令。列表第二个元素为 nil
或非 nil,分别对应使用 y-or-n-p
或 yes-or-no-p,第三个元素为询问内容。
应使用便捷函数 command-query
为命令启用询问功能。
从现在起允许 command(一个符号)无需特殊确认 即可执行,并修改用户初始化文件(参见 see The Init File) 使该设置在后续会话中生效。
从现在起执行 command 时需要特殊确认, 并修改用户初始化文件使该设置在后续会话中生效。
该变量的值应为一个函数。当用户交互调用被禁用命令时,
会调用该函数而非被禁用命令本身。它可通过
this-command-keys 获取用户输入按键,
从而确定具体命令。
该变量值也可为 nil,此时所有命令
(包括禁用命令)均正常执行。
默认值为一个询问用户是否继续的函数。
命令循环会保存已执行的复杂命令历史,
方便重复执行这些命令。复杂命令(complex command)
是指交互参数读取使用迷你缓冲区的命令。
包括所有 M-x 命令、M-: 命令,
以及 interactive 声明从迷你缓冲区
读取参数的命令。命令执行过程中显式使用
迷你缓冲区不会使其被视为复杂命令。
该变量的值为最近复杂命令列表,每个元素为 待求值的表达式。编辑会话期间会持续累积 所有复杂命令,达到最大长度后 (see 迷你缓冲历史) 新增元素时会删除最旧元素。
command-history
⇒ ((switch-to-buffer "chistory.texi")
(describe-key "^X^[")
(visit-tags-table "~/emacs/src/")
(find-tag "repeat-complex-command"))
该历史列表实际是迷你缓冲区历史的特例 (see 迷你缓冲历史), 特殊之处在于元素是表达式而非字符串。
有若干命令用于编辑和调用历史命令。
repeat-complex-command 与
list-command-history 在用户手册中说明
(see Repetition in The GNU Emacs Manual)。
在迷你缓冲区中可使用常规历史命令。
A 键盘宏(keyboard macro)是一套预设的输入事件序列, 可被视为一条命令,并可作为某个键的定义。键盘宏的 Lisp 表述形式是 一个包含事件的字符串或向量。请不要将键盘宏与 Lisp 宏混淆 (see 宏)。
该函数将 kbdmacro 作为事件序列来执行。 如果 kbdmacro 是一个字符串或向量,那么其中的事件会被 完全如同由用户输入那样地执行。该序列 不 要求是单一的键序列; 通常,一个键盘宏的定义由多个键序列拼接而成。
如果 kbdmacro 是一个符号(symbol),则其函数定义将被用作 kbdmacro。如果该定义又是另一个符号,则此过程会重复进行。 最终的结果应当是一个字符串或向量。如果结果既不是符号、字符串也不是向量, 则会发出错误信号。
参数 count 是重复次数(repeat count);
kbdmacro 将被执行相应的次数。
如果省略 count 或其值为 nil,
则 kbdmacro 仅执行一次。
如果其值为 0,则 kbdmacro 将反复执行,
直到遇到错误或搜索失败为止。
如果 loopfunc 非 nil,它是一个无参函数,
会在宏的每次迭代执行之前被调用。
若 loopfunc 返回 nil,则宏的执行将停止。
关于使用 execute-kbd-macro 的示例,
see 读取单个事件。
该变量包含当前正在执行的键盘宏的定义字符串或向量。
若当前没有执行任何宏,其值为 nil。
一个命令可以通过检测此变量,
使其在由正在执行的宏调用时表现出不同的行为。
请勿手动设置此变量。
当且仅当正在定义一个键盘宏时,该变量的值为非 nil。
一个命令可以通过检测此变量,
使其在宏定义过程中表现出不同的行为。
当向现有宏的定义中追加内容时,该变量的值为 append。
命令 start-kbd-macro、kmacro-start-macro
和 end-kbd-macro 会设置该变量—请勿手动设置它。
该变量始终是当前终端(terminal)的本地变量,不能成为缓冲区本地(buffer-local)的。 See Multiple Terminals。
该变量存放最近一次定义的键盘宏的定义。其值为字符串、向量或 nil。
该变量始终是当前终端的局部变量,不能设为缓冲区局部变量。See Multiple Terminals。
该普通钩子会在键盘宏终止时运行,无论终止原因是什么(执行到宏末尾,或因错误提前结束宏)。
输入事件的命令绑定记录在名为 按键映射(keymaps) 的数据结构中。按键映射中的每一项会将单个事件类型关联(或称 绑定(binds))到另一个按键映射或某个命令。当某个事件类型被绑定到一个按键映射时,该按键映射会被用于查找下一个输入事件;这一过程会持续进行,直到找到对应的命令。整个过程被称为 按键查找(key lookup)。
按键映射(keymap)是一种 Lisp 数据结构,用于为各类按键序列指定 按键绑定 (key binding)。
单个按键映射会直接为独立的事件定义绑定规则。当一个按键序列仅包含单个事件时, 其在该按键映射中的绑定关系,就是此按键映射针对该事件的定义。更长按键序列的绑定 关系则通过迭代过程查找:首先查找第一个事件的定义(该定义本身必须是一个按键映射); 接着在这个按键映射中查找第二个事件的定义,以此类推,直至处理完该按键序列中的所有事件。
若某个按键序列的绑定对象是一个按键映射,我们便称该按键序列为 前缀键
(prefix key)。反之,则称其为 完整键(complete key)(因为无法再为其添加更多事件)。
若绑定值为 nil,则称该按键为 未定义键(undefined key)。前缀键的示例有
C-c、C-x 和 C-x 4。已定义的完整键示例有 X、RET 和 C-x 4 C-f。
未定义的完整键示例有 C-x C-g 和 C-c 3。See 前缀键。
查找按键序列绑定关系的规则有一个前提:中间绑定(为最后一个事件之前的所有事件找到的绑定) 必须均为按键映射;若该前提不成立,则该事件序列无法构成一个独立单元——它并非真正意义上的 单个按键序列。换言之,从任意合法按键序列的末尾移除一个或多个事件后,得到的结果必须始终是 一个前缀键。例如,C-f C-n 并非合法按键序列;因为 C-f 不是前缀键,所以以 C-f 开头的更长序列也无法成为合法按键序列。
可用的多事件按键序列集合取决于前缀键的绑定关系;因此,不同按键映射对应的可用序列可能不同, 且当绑定关系发生变更时,该集合也会随之改变。但单事件序列始终是合法按键序列,因为其有效性 不依赖任何前缀键。
在任意时刻,都会有若干个主按键映射处于 激活(active)状态——即正用于查找按键绑定的状态。 这些映射包括:全局映射(global map),由所有缓冲区共享;局部按键映射(local keymap), 通常与特定的主模式关联;以及零个或多个 次要模式按键映射(minor mode keymaps), 归属于当前启用的次要模式(并非所有次要模式都有对应的按键映射)。局部按键映射的绑定会遮蔽 (即优先级高于)对应的全局绑定,而次要模式按键映射则会同时遮蔽局部和全局按键映射。 See 活跃按键映射表。
重新绑定按键的方式是修改其在按键映射中的条目。如果你在全局按键映射中修改了某个绑定,
该修改会在所有缓冲区生效(尽管在那些使用局部映射遮蔽全局绑定的缓冲区中,不会产生直接效果)。
如果你修改当前缓冲区的局部映射,这通常会影响所有使用同一主模式的缓冲区。
keymap-global-set 和 keymap-local-set 函数是执行这些操作的便捷接口
(see 按键绑定相关命令)。你也可以使用更通用的函数 keymap-set,
此时必须显式指定要修改的映射。
在为 Lisp 程序选择需要重新绑定的按键序列时,请遵循 Emacs 中各类按键的使用规范 (see Key Binding Conventions)。
如果 keymap 不是合法的按键映射,或 key 不是有效按键, 下述函数都会抛出错误。
key 是表示单个按键或一系列按键的字符串,且必须满足 key-valid-p。
按键之间以单个空格分隔。
每个按键可以是单个字符,或是用尖括号包裹的事件名称。 此外,任意按键前均可添加一个或多个修饰键。 最后,少数字符拥有专用的简写语法。以下是一些按键序列示例:
按键 f。
由 S、o、m 组成的三键序列。
先按带 Control 修饰的 c,再按 o 的两键序列。
带 Hyper 修饰的方向左键 left。
带 Meta 修饰的回车键 return。
同时带 Control 与 Meta 修饰的空格键 space。
拥有专用简写语法的按键仅有:NUL、RET、TAB、LFD、 ESC、SPC 和 DEL。
修饰键必须按字母顺序指定: ‘A-C-H-M-S-s’,对应顺序为 ‘Alt-Control-Hyper-Meta-Shift-super’。
该函数在 keymap 中为 key 设置绑定。
(若 key 长度超过一个事件,修改实际上会作用于从 keymap 可达的另一按键映射。)
参数 binding 可以是任意 Lisp 对象,但只有特定类型具有实际意义。
(有效类型列表参见 按键查找。)
keymap-set 返回的值为 binding。
若 key 为 <t>,则会设置 keymap 中的默认绑定。 当某个事件自身无绑定时,Emacs 命令循环会使用该按键映射的默认绑定(若存在)。
key 的每一级前缀都必须是前缀键(即绑定到一个按键映射)或未定义,
否则会抛出错误。若 key 的某一级前缀未定义,
keymap-set 会将其定义为前缀键,从而使 key 的后续部分可按指定方式定义。
若 keymap 中此前不存在 key 的绑定,新绑定会添加到 keymap 开头。 按键映射中绑定的顺序对键盘输入无影响,但对菜单按键映射至关重要(see 菜单按键映射)。
该函数是 keymap-set 的逆操作,它会取消 keymap 中 key 的绑定,
效果等同于将绑定设为 nil。若要彻底删除该绑定,可将 remove 指定为非 nil。
这仅在 keymap 存在父映射时存在区别:若仅在子映射中取消按键绑定,
该按键仍会遮蔽父映射中的同名按键;而使用 remove 则可使父映射中的对应按键生效。
注意:在 init 文件中,用户可以使用带非 nil 参数 remove 的 keymap-unset;
Emacs 扩展包应尽量避免使用该用法,因为扩展包本就完全掌控自身的按键映射,
不应修改其他包的按键映射。
下面的示例创建一个稀疏按键映射并在其中添加若干绑定:
(setq map (make-sparse-keymap))
⇒ (keymap)
(keymap-set map "C-f" 'forward-char)
⇒ forward-char
map
⇒ (keymap (6 . forward-char))
;; Build sparse submap for C-x and bind f in that.
(keymap-set map "C-x f" 'forward-word)
⇒ forward-word
map
⇒ (keymap
(24 keymap ; C-x
(102 . forward-word)) ; f
(6 . forward-char)) ; C-f
;; Bind C-p to thectl-x-map. (keymap-set map "C-p" ctl-x-map) ;;ctl-x-map⇒ [nil ... find-file ... backward-kill-sentence]
;; Bind C-f to foo in the ctl-x-map.
(keymap-set map "C-p C-f" 'foo)
⇒ 'foo
map
⇒ (keymap ; Note foo in ctl-x-map.
(16 keymap [nil ... foo ... backward-kill-sentence])
(24 keymap
(102 . forward-word))
(6 . forward-char))
可以看到,为 C-p C-f 设置新绑定实际上是修改了 ctl-x-map 中的条目,
这会同时改变默认全局映射中 C-p C-f 与 C-x C-f 的绑定。
keymap-set 是在按键映射中定义按键的通用工具。
但在编写模式时,常常需要一次性绑定大量按键,逐个使用 keymap-set 会繁琐且易出错。
此时可以使用 define-keymap,它会创建按键映射并批量绑定多个按键。
See 创建按键映射。
函数 substitute-key-definition 会遍历按键映射,
查找绑定到某一命令的按键并将其重新绑定到另一命令。
另一种更简洁且通常能达到相同效果的方式是将一个命令重映射为另一个命令
(see 命令重映射)。
该函数会将 keymap 中所有绑定到 olddef 的按键,
替换为绑定到 newdef。也就是说,olddef 出现的所有位置都会被替换为 newdef。
函数返回 nil。
例如,在使用默认绑定的 Emacs 中,以下代码会重新定义 C-x C-f:
(substitute-key-definition 'find-file 'find-file-read-only (current-global-map))
若 oldmap 非 nil,会改变 substitute-key-definition 的行为:
由 oldmap 中的绑定决定需要重新绑定哪些按键,而重绑定操作仍发生在 keymap 中,
而非 oldmap。这样你可以依据另一映射的绑定规则来修改当前映射。例如:
(substitute-key-definition 'delete-backward-char 'my-funny-delete my-map global-map)
这段代码会在 my-map 中,为所有全局绑定到标准删除命令的按键设置自定义删除命令。
以下示例展示了替换前后的按键映射:
(setq map (list 'keymap
(cons ?1 olddef-1)
(cons ?2 olddef-2)
(cons ?3 olddef-1)))
⇒ (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1))
(substitute-key-definition 'olddef-1 'newdef map) ⇒ nil
map ⇒ (keymap (49 . newdef) (50 . olddef-2) (51 . newdef))
该函数通过将 self-insert-command 重映射为 undefined 命令
(see 命令重映射),修改完整按键映射 keymap 的内容。
其效果是取消所有可打印字符的绑定,从而禁止普通文本插入操作。
suppress-keymap 返回 nil。
若 nodigits 为 nil,则 suppress-keymap 会将数字键定义为执行
digit-argument,- 定义为执行 negative-argument;
否则会将它们与其他可打印字符一样设为未定义。
suppress-keymap 并不会完全禁止修改缓冲区,
因为它不会禁用 yank、quoted-insert 等命令。
若要完全禁止修改缓冲区,应将其设为只读(see Read-Only Buffers)。
由于该函数会修改 keymap,通常只应在新建的按键映射上使用。
对已用于其他用途的现有映射进行操作可能引发问题;
例如,对 global-map 执行该操作会导致大部分 Emacs 功能无法使用。
该函数可用于初始化不希望插入文本的主模式的局部按键映射。
但这类模式通常应继承自 special-mode(see 基础主模式),
其按键映射会自动继承已被禁用的 special-mode-map。
special-mode-map 的定义方式如下:
(defvar special-mode-map
(let ((map (make-sparse-keymap)))
(suppress-keymap map)
(keymap-set map "q" 'quit-window)
...
map))
每个按键映射都是一个列表,其首个元素(CAR)为符号 keymap。
列表的其余元素定义了该按键映射的按键绑定。函数定义为按键映射的符号本身也属于按键映射。
可使用函数 keymapp(见下文)检测一个对象是否为按键映射。
在按键映射开头的 keymap 符号之后,可出现以下几种类型的元素:
(type . binding)该元素为 type 类型的事件指定一个绑定。每个普通绑定都适用于特定事件类型(event type)的事件, 事件类型始终是一个字符或符号(See 事件分类)。在此类绑定中,binding 是一个命令。
(type item-name . binding)该元素指定的绑定同时也是一个简单菜单项,会在菜单中显示为 item-name(See 简单菜单项)。
(type item-name help-string . binding)这是一个带有帮助字符串 help-string 的简单菜单项。
(type menu-item . details)该元素指定的绑定同时也是一个扩展菜单项,支持更多功能特性(See 扩展菜单项)。
(t . binding) ¶该元素指定默认按键绑定(default key binding):所有未被按键映射中其他元素绑定的事件,都会使用 binding 作为其绑定。
默认绑定允许按键映射无需枚举所有可能的事件类型,即可为所有事件类型设置绑定。
带有默认绑定的按键映射会完全遮蔽所有低优先级的按键映射,但显式绑定为 nil 的事件除外(见下文)。
char-table若按键映射的某个元素是字符表(char-table),则它会为所有无修饰位的字符事件提供绑定 (see modifier bits):索引为 c 的元素即为字符 c 的绑定。 这是一种紧凑记录大量绑定的方式。包含此类字符表的按键映射被称为完整按键映射(full keymap), 其他按键映射则称为稀疏按键映射(sparse keymap)。
vector此类元素与字符表类似:索引为 c 的元素即为字符 c 的绑定。 但由于这种方式能绑定的字符范围受向量大小限制,且创建向量时会为从 0 开始的所有字符码分配空间, 因此除创建菜单按键映射(see 菜单按键映射,其绑定本身无实际意义)外,不应使用该格式。
string ¶除指定按键绑定的元素外,按键映射还可包含字符串类型的元素。该字符串被称为整体提示字符串 (overall prompt string),使按键映射可被用作菜单(See 定义菜单)。
(keymap …)若按键映射的某个元素本身也是一个按键映射,则等效于将该内部按键映射内联到外部按键映射中。
这一机制用于实现多重继承,例如 make-composed-keymap 函数即采用此方式。
当绑定值为 nil 时,该元素不构成有效定义,但会优先于默认绑定或父映射中的绑定生效。
另一方面,值为 nil 的绑定不会覆盖低优先级的按键映射;
因此,若局部映射中某按键的绑定为 nil,Emacs 会使用全局映射中的对应绑定。
按键映射不会直接记录元字符(meta characters)的绑定。
在按键查找时,元字符会被视为两个字符组成的序列,第一个字符为 ESC
(或当前 meta-prefix-char 的值)。因此,按键 M-a 在内部会被表示为 ESC a,
其全局绑定可在 esc-map 中 a 对应的位置找到(See 前缀键)。
这种转换仅适用于字符,不适用于功能键或其他输入事件; 因此,M-end 与 ESC end 毫无关联。
以下是 Lisp 模式的局部按键映射示例(属于稀疏按键映射)。 它为 DEL、C-c C-z、C-M-q 和 C-M-x 定义了绑定 (实际值还包含一个菜单绑定,为简洁起见此处省略)。
lisp-mode-map ⇒
(keymap
(3 keymap
;; C-c C-z
(26 . run-lisp))
(27 keymap
;; C-M-x, treated as ESC C-x
(24 . lisp-send-defun))
;; This part is inherited from lisp-mode-shared-map.
keymap
;; DEL
(127 . backward-delete-char-untabify)
(27 keymap
;; C-M-q, treated as ESC C-q
(17 . indent-sexp)))
该函数在 object 为按键映射时返回 t,否则返回 nil。
更准确地说,该函数会检测对象是否为首个元素是 keymap 的列表,
或函数定义满足 keymapp 的符号。
(keymapp '(keymap))
⇒ t
(fset 'foo '(keymap))
(keymapp 'foo)
⇒ t
(keymapp (current-global-map))
⇒ t
本节介绍用于创建按键映射的函数。
该函数创建并返回一个新的空稀疏按键映射(稀疏按键映射是日常使用中最常用的类型)。
与 make-keymap 不同,新创建的按键映射不包含字符表(char-table),且未绑定任何事件。
(make-sparse-keymap)
⇒ (keymap)
若指定了 prompt 参数,该值会成为按键映射的整体提示字符串。 此参数仅应在创建菜单按键映射时指定(see 定义菜单)。 带有整体提示字符串的按键映射在激活并用于查找下一个输入事件时, 总会弹出鼠标菜单或键盘菜单。不要为主模式或次要模式的主映射指定整体提示字符串, 否则命令循环会在每次执行时都弹出键盘菜单。
该函数创建并返回一个新的完整按键映射。
该按键映射包含一个字符表(see 字符表),
为所有无修饰符的字符分配了绑定槽位。新按键映射初始时将所有这些字符绑定为 nil,
且未绑定任何其他类型的事件。参数 prompt 的作用与 make-sparse-keymap 中相同,
用于指定提示字符串。
(make-keymap)
⇒ (keymap #^[nil nil keymap nil nil nil ...])
当需要存储大量绑定时,完整按键映射比稀疏按键映射效率更高; 而仅需少量绑定时,稀疏按键映射则更为合适。
你可以使用上述函数创建按键映射,
再通过 keymap-set(see 修改按键绑定)为该映射指定按键绑定。
但在编写模式时,常常需要一次性绑定大量按键,
逐个使用 keymap-set 会繁琐且易出错。
此时可使用 define-keymap,它能一次性完成按键映射的创建与多组按键的绑定。
以下是一个基础示例:
(define-keymap "n" #'forward-line "f" #'previous-line "C-c C-c" #'quit-window)
该函数会创建一个新的稀疏按键映射,在其中定义 pairs 中的按键绑定, 并返回这个新映射。若 pairs 中存在重复的按键绑定,函数会抛出错误。
pairs 是由按键绑定与按键定义交替组成的列表,格式与 keymap-set 接受的参数一致。
此外,按键可以是特殊符号 :menu,此时对应的定义应为 easy-menu-define 可接受的菜单定义
(see 简易菜单)。以下是该用法的简短示例:
(define-keymap :full t
"g" #'eww-reload
:menu '("Eww"
["Exit" quit-window t]
["Reload" eww-reload t]))
在按键/定义对之前,可使用若干关键字来修改新按键映射的特性。
若 define-keymap 调用中未指定某特性关键字,则该特性的默认值为 nil。
可用的特性关键字如下:
:full若值为非 nil,则创建字符表类型的按键映射(等效于 make-keymap),
而非稀疏按键映射(等效于 make-sparse-keymap,see 创建按键映射)。
默认创建稀疏按键映射。
:parent若值为非 nil,则其值应为一个按键映射,将被用作新映射的父映射(see 继承与按键映射表)。
:keymap若值为非 nil,则其值应为一个已存在的按键映射。此时函数不会创建新映射,
而是修改指定的现有映射。
:suppress若值为非 nil,则会通过 suppress-keymap 禁用该按键映射
(see 修改按键绑定)。默认情况下,数字键和减号键不会被禁用;
若该值为 nodigits,则数字键和减号键会与其他字符一样被禁用。
:name若值为非 nil,则其值应为一个字符串。当通过 x-popup-menu 将该映射用作菜单时,
该字符串会作为菜单名称(see Pop-Up Menus)。
:prefix若值为非 nil,则其值应为一个符号,将被用作前缀命令(see 前缀键)。
此时 define-keymap 返回该符号而非映射本身。
在实际使用中,按键映射最常见的用法是将其绑定到变量上。
几乎所有模式都会这么做——名为 foo 的模式通常会有一个名为 foo-mode-map 的变量。
该宏将 name 定义为变量,把 options 和 pairs 传递给 define-keymap,
并将返回结果设为该变量的默认值。若 pairs 中存在重复的按键绑定,宏会抛出错误。
options 的格式与 define-keymap 中的关键字一致,
但新增了 :doc 关键字,用于为定义的变量提供文档字符串。
示例如下:
(defvar-keymap eww-textarea-map :parent text-mode-map :doc "Keymap for the eww text area." "RET" #'forward-line "TAB" #'shr-next-link)
可通过为按键映射中的命令设置 repeat-map 属性,
将其标记为 ‘可重复执行’ (即可在 repeat-mode 中使用),示例如下:
(put 'undo 'repeat-map 'undo-repeat-map)
其中该属性的值为 repeat-mode 要使用的映射。
为避免重复调用 put 函数,defvar-keymap 还提供了 :repeat 关键字,
可用于指定映射中哪些命令可在 repeat-mode 中使用。
该关键字支持以下取值:
t表示映射中所有命令均可重复执行,这是最常用的用法。
(:enter (commands ...) :exit (commands ...) :hints ((command . "hint") ...))指定 :enter 列表中的命令会进入 repeat-mode,
:exit 列表中的命令会退出重复模式。
若 :enter 列表为空,则映射中所有命令都会进入 repeat-mode。
若需要为当前定义的映射中不存在、但需设置 repeat-map 属性的命令配置该特性,
可在该列表中指定这些命令。
若 :exit 列表为空,则映射中无命令会退出 repeat-mode。
若当前定义的映射中包含不应设置 repeat-map 属性的命令,
可在该列表中指定这些命令。
:hints 列表可包含 cons 对,其中首个元素(CAR)为命令,
第二个元素(CDR)为字符串,会在回显区中与可重复执行的按键一同显示。
例如,要让 u 重复执行 undo 命令,以下两段代码等效:
(defvar-keymap undo-repeat-map "u" #'undo) (put 'undo 'repeat-map 'undo-repeat-map)
和
(defvar-keymap undo-repeat-map :repeat t "u" #'undo)
当映射中有多个命令且均需设为可重复执行时,推荐使用后一种写法。
该函数返回 keymap 的副本。此函数几乎很少用到。 若你需要一个基于现有映射、仅做少量修改的新映射, 应使用映射继承而非复制,例如:
(let ((map (make-sparse-keymap))) (set-keymap-parent map <theirmap>) (keymap-set map ...) ...)
执行 copy-keymap 时,
直接作为 keymap 中绑定存在的所有按键映射都会被递归复制,
且递归层级无限制。但当某个字符的定义是一个函数定义为按键映射的符号时,
不会发生递归复制——该符号会直接出现在新副本中。
(setq map (copy-keymap (current-local-map))) ⇒ (keymap
;; (This implements meta characters.)
(27 keymap
(83 . center-paragraph)
(115 . center-line))
(9 . tab-to-tab-stop))
(eq map (current-local-map))
⇒ nil
(equal map (current-local-map))
⇒ t
一个按键映射表(keymap)可以继承另一个按键映射表的绑定关系,我们将后者称为 父按键映射表(parent keymap)。这类按键映射表的结构如下:
(keymap elements... . parent-keymap)
其作用是,该按键映射表会继承 parent-keymap 的所有绑定关系(无论按键查询时 这些绑定关系具体是什么),同时可通过 elements 新增绑定关系或覆盖原有绑定。
若你使用 keymap-set 或其他按键绑定函数修改 parent-keymap 中的绑定关系,
这些修改后的绑定会在继承该映射表的子映射表中生效——除非被 elements 定义的绑定
关系覆盖。反之则不成立:若使用 keymap-set 修改继承方按键映射表的绑定关系,
这些变更仅会记录在 elements 中,不会对 parent-keymap 产生任何影响。
构建带父映射表的按键映射表的规范方式是使用 set-keymap-parent;若你的代码中
存在直接构造带父映射表的按键映射表的逻辑,请将程序修改为使用 set-keymap-parent
实现。
该函数返回 keymap 的父按键映射表。若 keymap 无父映射表,
keymap-parent 返回 nil。
该函数将 keymap 的父按键映射表设置为 parent,并返回 parent。
若 parent 为 nil,则该函数会移除 keymap 的所有父映射表。
若 keymap 包含子映射表(即前缀键的绑定关系),这些子映射表也会获得新的父按键映射表, 且新父映射表会遵循 parent 为这些前缀键指定的配置。
以下示例展示如何创建一个继承自 text-mode-map 的按键映射表:
(let ((map (make-sparse-keymap))) (set-keymap-parent map text-mode-map) map)
非稀疏按键映射表(non-sparse keymap)也可拥有父映射表,但这一用法实用价值不高。
非稀疏按键映射表会为所有无修饰位的数字字符编码显式指定绑定关系(即便绑定值为 nil),
因此这些字符的绑定关系永远不会从父按键映射表继承。
有时你需要创建一个从多个映射表继承的按键映射表,可通过函数 make-composed-keymap
实现这一需求。
该函数返回一个由已有按键映射表(一个或多个)maps 组合而成的新映射表,
该新映射表可选择性地从父按键映射表 parent 继承绑定关系。maps 可以是单个
按键映射表,也可以是包含多个映射表的列表。在新映射表中查询按键时,Emacs 会依次遍历
maps 中的每个映射表,再查询 parent,并在找到第一个匹配项时停止。
若 maps 中任意一个映射表对某按键的绑定值为 nil,该值会覆盖 parent
中对应的绑定关系,但不会覆盖 maps 中其他映射表的非 nil 绑定。
例如,以下代码展示了 Emacs 如何设置 help-mode-map 的父映射表,
使其同时从 button-buffer-map 和 special-mode-map 继承:
(defvar-keymap help-mode-map
:parent (make-composed-keymap button-buffer-map
special-mode-map)
...)
前缀键(prefix key)是一种按键序列,其绑定对象为一个按键映射表。
该映射表定义了在前缀键基础上继续输入的按键序列所对应的行为。
例如,C-x 是一个前缀键,它使用一个同样保存在变量 ctl-x-map
中的按键映射表。该映射表定义了所有以 C-x 开头的按键序列的绑定。
部分标准 Emacs 前缀键所使用的映射表同样可以通过 Lisp 变量访问:
esc-map 是 ESC 前缀键的全局按键映射表。因此,
所有元字符(meta character)的全局定义实际上都存放在这里。
该映射表同时也是函数 ESC-prefix 的函数定义。
help-map 是 C-h 前缀键的全局按键映射表。
mode-specific-map 是前缀键 C-c 的全局按键映射表。
该映射表实际是全局有效的,而非与具体主模式相关,但其名称能在
C-h b(display-bindings)的输出中为 C-c
提供有用的提示信息,因为该前缀键主要用于主模式专属绑定。
ctl-x-map 是 C-x 前缀键的全局按键映射表。
该映射表可通过符号 Control-X-prefix 的函数单元访问。
mule-keymap 是 C-x RET 前缀键的全局按键映射表。
ctl-x-4-map 是 C-x 4 前缀键的全局按键映射表。
ctl-x-5-map 是 C-x 5 前缀键的全局按键映射表。
2C-mode-map 是 C-x 6 前缀键的全局按键映射表。
tab-prefix-map 是 C-x t 前缀键的全局按键映射表。
vc-prefix-map 是 C-x v 前缀键的全局按键映射表。
goto-map 是 M-g 前缀键的全局按键映射表。
search-map 是 M-s 前缀键的全局按键映射表。
前缀键所绑定的按键映射表用于查找前缀键之后的输入事件。
(该绑定也可以是一个符号,其函数定义为一个按键映射表。效果相同,
只是该符号可作为此前缀键的名称。)因此,C-x 的绑定是符号
Control-X-prefix,其函数单元中保存着 C-x 系列命令的按键映射表。
(该映射表同时也是变量 ctl-x-map 的值。)
前缀键定义可以出现在任意活跃按键映射表中。 C-c、C-x、C-h 和 ESC 作为前缀键的定义 出现在全局映射表中,因此这些前缀键始终可用。 主模式和次模式可以在局部映射表或次模式映射表中为某个按键设置前缀键定义, 从而将其重新定义为前缀键。See 活跃按键映射表。
若一个按键在多个活跃映射表中均被定义为前缀键,则这些定义实际上会被合并: 次模式按键映射表中的定义优先级最高,其次是局部映射表中的前缀定义, 最后是全局映射表中的定义。
在下例中,我们在局部按键映射表中将 C-p 设置为前缀键,
使其行为与 C-x 完全一致。于是 C-p C-f 的绑定为函数
find-file,与 C-x C-f 相同。与之相对,按键序列
C-p 9 在任何活跃映射表中都不存在绑定。
(use-local-map (make-sparse-keymap))
⇒ nil
(keymap-local-set "C-p" ctl-x-map)
⇒ (keymap #^[nil nil keymap ...
(keymap-lookup nil "C-p C-f")
⇒ find-file
(keymap-lookup nil "C-p 9")
⇒ nil
该函数为 symbol 做好充当前缀键绑定的准备:
它会创建一个稀疏按键映射表,并将其设为 symbol 的函数定义。
之后将某按键序列绑定到 symbol 即可使该按键序列成为前缀键。
函数返回值为 symbol。
该函数同时会将 symbol 设置为变量,其值为上述按键映射表。
但若 mapvar 非 nil,则会将 mapvar 设为该映射表的变量名。
若 prompt 非 nil,则将其设为该按键映射表的整体提示字符串。
菜单按键映射表通常需要指定提示字符串(see 定义菜单)。
Emacs 内部包含大量按键映射表,但在任意时刻只有少数映射表处于 活跃(active)状态。当 Emacs 接收用户输入时,会先对输入事件进行转换 (see 事件序列翻译键盘映射),然后在活跃按键映射表中查找对应的按键绑定。
通常情况下,活跃按键映射表按优先级顺序为:
(i) 由 keymap 属性指定的映射表,
(ii) 已启用的次模式的映射表,
(iii) 当前缓冲区的局部按键映射表,
(iv) 全局按键映射表。
Emacs 会在所有这些映射表中依次查找每个输入按键序列。
在上述常见映射表中,优先级最高的是光标位置处文本或覆盖层
的 keymap 属性指定的映射表(若存在)。
(对于鼠标输入事件,Emacs 使用事件位置而非光标位置;
see 搜索活跃按键映射表.)
次高优先级的是已启用次模式指定的按键映射表。
这些映射表(若存在)由变量
emulation-mode-map-alists、
minor-mode-overriding-map-alist
和 minor-mode-map-alist 指定。
See 控制活跃按键映射表。
再下一优先级是缓冲区的局部按键映射表(local keymap),
其中包含该缓冲区专属的按键绑定。小缓冲区同样拥有局部按键映射表
(see 迷你缓冲区简介)。
若光标位置存在 local-map 文本或覆盖层属性,
则该属性指定的映射表将替代缓冲区默认的局部映射表生效。
局部按键映射表通常由缓冲区的主模式设置,
同一主模式下的所有缓冲区共享同一份局部映射表。
因此,若在某个缓冲区中调用 keymap-local-set
(see 按键绑定相关命令)修改局部映射表,
会同时影响其他同主模式缓冲区的局部映射表。
最后,全局按键映射表(global keymap)包含与当前缓冲区无关的通用按键绑定,
例如 C-f。它始终处于活跃状态,并绑定到变量 global-map。
除上述常见映射表外,Emacs 还为程序提供了使其他映射表活跃的特殊方式。
其一,变量 overriding-local-map 指定一个映射表,
用于替换除全局映射表外的所有常规活跃映射表。
其二,终端局部变量 overriding-terminal-local-map
指定一个优先级高于所有其他映射表(包括 overriding-local-map)
的映射表;该变量通常用于模态/临时按键绑定(函数 set-transient-map
为此提供了便捷接口)。See 控制活跃按键映射表。
使映射表活跃并非使用它们的唯一方式。
按键映射表还可用于其他场景,例如在 read-key-sequence
内部对事件进行转换。See 事件序列翻译键盘映射。
部分标准按键映射表列表参见 See Standard Keymaps。
该函数返回当前环境下命令循环用于查找按键序列的活跃映射表列表。
通常它会忽略 overriding-local-map 和
overriding-terminal-local-map,
但若 olp 非 nil,则会将其纳入考虑。
position 可选为 event-start 返回的事件位置
或缓冲区位置,其作用与 keymap-lookup
(see keymap-lookup)中所述一致,
可能会改变所使用的映射表。
以下是一段伪 Lisp 代码,概括了 Emacs 搜索活跃按键映射表的流程:
(or (if overriding-terminal-local-map
(find-in overriding-terminal-local-map))
(if overriding-local-map
(find-in overriding-local-map)
(or (find-in (get-char-property (point) 'keymap))
(find-in-any emulation-mode-map-alists)
(find-in-any minor-mode-overriding-map-alist)
(find-in-any minor-mode-map-alist)
(if (get-char-property (point) 'local-map)
(find-in (get-char-property (point) 'local-map))
(find-in (current-local-map)))))
(find-in (current-global-map)))
其中 find-in 和 find-in-any 是伪函数,分别表示在单个按键映射表
和在关联列表(alist)形式的一组映射表中进行查找。
注意 set-transient-map 函数正是通过设置 overriding-terminal-local-map
来实现其功能的(see 控制活跃按键映射表)。
在上述伪代码中,如果按键序列以鼠标事件开头(see 鼠标事件),
则会使用该事件所在位置而非光标位置,并使用事件所在缓冲区而非当前缓冲区。
这尤其会影响 keymap 和 local-map 属性的查找方式。
如果鼠标事件发生在带有 display、before-string 或
after-string 属性的内嵌字符串上(see Properties with Special Meanings),
且该字符串的 keymap 或 local-map 属性非 nil,
则该属性会覆盖底层缓冲区文本对应的属性(即底层文本的属性会被忽略)。
当在某个活跃映射表中找到按键绑定,且该绑定是一个命令时,搜索结束并执行该命令。 但如果该绑定是一个带有值的符号或字符串,Emacs 会用该变量值或字符串替换输入按键序列, 并重新开始在活跃映射表中搜索。See 按键查找。
最终找到的命令还可能被重映射。See 命令重映射。
该变量保存默认的全局按键映射表,负责将 Emacs 键盘输入映射到命令。
全局映射表通常就是该映射表。默认全局映射表是一个完整映射表,
它将 self-insert-command 绑定到所有可打印字符。
修改全局映射表中的绑定是常见做法,但不应该给该变量赋予初始映射表以外的值。
该函数返回当前全局按键映射表。除非你修改其中某一个,
否则它与 global-map 的值相同。
返回值是引用而非副本;若对其使用 keymap-set 或其他函数,
会直接修改全局按键绑定。
(current-global-map)
⇒ (keymap [set-mark-command beginning-of-line ...
delete-backward-char])
该函数返回当前缓冲区的局部按键映射表,若无则返回 nil。
下例展示了 *scratch* 缓冲区(使用 Lisp Interaction 模式)
的映射表是一个稀疏映射表,其中 ESC(ASCII 码 27)对应的条目是另一个稀疏映射表。
(current-local-map)
⇒ (keymap
(10 . eval-print-last-sexp)
(9 . lisp-indent-line)
(127 . backward-delete-char-untabify)
(27 keymap
(24 . eval-defun)
(17 . indent-sexp)))
current-local-map 返回的是局部映射表的引用而非副本;
若对其使用 keymap-set 等函数,会直接修改局部绑定。
该函数返回当前已启用次模式的按键映射表列表。
该函数将 keymap 设置为新的当前全局按键映射表。返回 nil。
修改全局映射表的情况非常少见。
该函数将 keymap 设置为当前缓冲区新的局部按键映射表。
若 keymap 为 nil,则该缓冲区不再拥有局部映射表。
use-local-map 返回 nil。大多数主模式命令都会使用该函数。
该变量是一个关联列表,描述根据某些变量的值决定是否活跃的按键映射表。 其元素格式如下:
(variable . keymap)
只要 variable 的值非 nil,keymap 就处于活跃状态。
通常 variable 是用于启用或禁用某个次模式的变量。See 按键映射与次要模式。
注意 minor-mode-map-alist 的元素结构与 minor-mode-alist 不同。
映射表必须是元素的 CDR;以映射表为第二个元素的普通列表无效。
CDR 可以是一个按键映射表(列表),也可以是一个函数定义为按键映射表的符号。
当多个次模式映射表同时活跃时,minor-mode-map-alist 中靠前的元素优先级更高。
但你在设计次模式时应避免相互冲突,这样顺序便不再重要。
有关次模式的更多信息,参见 按键映射与次要模式。
另请参见 minor-mode-key-binding(see 按键查找函数)。
该变量允许主模式覆盖特定次模式的按键绑定。
其元素格式与 minor-mode-map-alist 相同:(variable . keymap)。
如果某个变量同时出现在本列表与 minor-mode-map-alist 中,
本列表中指定的映射表会完全替换后者中同一变量对应的映射表。
minor-mode-overriding-map-alist 在所有缓冲区中自动成为局部变量。
若该变量非 nil,它保存的按键映射表将替代缓冲区局部映射表、
任何文本属性或覆盖层映射表以及所有次模式映射表生效。
如果指定该映射表,它会覆盖原本活跃的所有其他映射表,全局映射表除外。
若该变量非 nil,它保存的映射表优先级高于 overriding-local-map、
局部映射表、文本/覆盖层映射表以及所有次模式映射表。
该变量始终是当前终端局部的,不能设为缓冲区局部。See Multiple Terminals。 它用于实现增量搜索模式。
若该变量非 nil,overriding-local-map 或
overriding-terminal-local-map 会影响菜单栏显示。
默认值为 nil,因此这些映射表变量对菜单栏无影响。
注意即使不影响菜单栏显示,这两个映射表变量依然会影响通过菜单栏输入的按键序列执行。 因此当菜单栏按键事件到来时,应在查找并执行前清空这些变量。 使用这些变量的模式通常都会这样处理:它们对无法处理的事件执行“反读”并退出。
该变量保存用于特殊事件的按键映射表。
如果某类事件在该映射表中有绑定,则它属于特殊事件,
其绑定会由 read-event 直接运行。See 特殊事件。
该变量保存一组用于模拟模式的按键映射表关联列表。
适用于使用多个次模式映射表的模式或包。
每个元素都是一个格式与含义同 minor-mode-map-alist 的映射表关联列表,
或是一个变量值为此类列表的符号。
每个列表中的活跃映射表优先级高于 minor-mode-map-alist
和 minor-mode-overriding-map-alist。
该函数将 keymap 添加为临时(transient)按键映射表, 使其在接下来一次或多次按键时优先级高于其他映射表。
默认情况下,keymap 只使用一次,用于查找下一个按键。
若可选参数 keep-pred 为 t,则只要用户输入该映射表中定义的按键,
映射表就保持活跃;当用户输入一个不在该映射表 keymap 中的按键时,临时映射表被禁用,
并对该按键继续执行正常查找流程。
keep-pred 也可以是一个函数。这种情况下,在 keymap 活跃期间,
每次执行命令前都会调用该无参函数;若返回非 nil,则保持 keymap 活跃。
可选参数 on-exit 若非 nil,指定一个无参函数,
在 keymap 被禁用后执行。
可选参数 message 指定激活临时映射表后显示的提示信息。
若为字符串,则作为提示信息的格式串,其中 ‘%k’ 会被替换为临时映射表中的按键列表。
其他非 nil 的 message 值表示使用默认格式 ‘Repeat with %k’。
若可选参数 timeout 非 nil,应为一个数字,
指定在空闲多少秒后禁用 keymap。
变量 set-transient-map-timeout 的值(若非 nil)会覆盖该参数。
该函数的实现方式是在变量 overriding-terminal-local-map 中添加或移除
keymap,该变量优先级高于所有其他活跃映射表(see 搜索活跃按键映射表)。
按键查找(Key lookup)是从指定键盘映射中查找按键序列绑定的过程。 绑定的执行或使用不属于按键查找的范畴。
按键查找仅使用按键序列中每个事件的事件类型;
事件的其余部分会被忽略。实际上,用于按键查找的按键序列可以仅通过其类型(一个符号)
来指定鼠标事件,而非完整的事件(一个列表)。See 输入事件。
这样的按键序列不足以让 command-execute 运行,
但足以用于按键查找或重新绑定。
当按键序列包含多个事件时,按键查找会按顺序处理事件: 先找到第一个事件的绑定,且该绑定必须是键盘映射; 然后在该键盘映射中查找第二个事件的绑定,依此类推, 直到按键序列中的所有事件处理完毕。 (为最后一个事件查找到的绑定可以是键盘映射,也可以不是。) 因此,按键查找过程是基于在键盘映射中查找单个事件这一更简单的过程定义的。 具体行为取决于该键盘映射中与事件关联的对象类型。
我们使用术语 keymap entry 来描述在键盘映射中查找事件类型所得到的值。
(这不包括菜单项的键盘映射元素中的项字符串和其他附加元素,
因为 keymap-lookup 及其他按键查找函数不会在返回值中包含这些内容。)
虽然任意 Lisp 对象都可以作为键盘映射项存入键盘映射,
但并非所有对象对按键查找都有意义。
以下是有意义的键盘映射项类型表:
nil ¶nil 表示查找过程中已使用的事件构成了未定义按键。
当键盘映射完全未提及某事件类型且无默认绑定时,
等价于该事件类型的绑定为 nil。
至此在查找过程中使用的事件构成了一个完整的键, 而 command 是该键的绑定。See 什么是函数?。
该数组(可以是字符串或向量)是一个键盘宏。至此在查找过程中使用的事件 构成了一个完整的键,而该数组是该键的绑定。更多信息参见 键盘宏。
至此在查找过程中使用的事件构成了一个前缀键。按键序列的下一个 事件将在 keymap 中进行查找。
列表的含义取决于其包含的内容:
keymap,那么该列表
是一个按键映射表,并会被当作按键映射表处理(见上文)。
lambda,那么该列表是一个
lambda 表达式。它会被认定为一个函数,并按函数方式处理(见上文)。
为了能作为按键绑定正常执行,
该函数必须是一个命令—即它必须包含 interactive
规范说明。See 定义命令。
symbol 的函数定义会被用来替代 symbol 本身。如果该函数定义同样是一个符号, 则此过程会重复进行,次数不限。 最终这一过程应指向一个属于按键映射表、命令 或键盘宏的对象。
需要注意的是,按键映射表和键盘宏(字符串及向量)并非
有效的函数,因此若一个符号的函数定义是按键映射表、字符串或向量,
则该符号作为函数是无效的。但作为
按键绑定,它是有效的。如果该定义是一个键盘宏,
那么该符号也可作为 command-execute 的有效参数
(see 交互式调用)。
符号 undefined 值得特别说明:它表示将该键视为未定义状态。
严格来说,该键是已定义的,其绑定的命令就是 undefined;
但该命令的行为与未定义键的默认行为一致:
它会响铃(通过调用 ding 函数),但不会触发错误信号。
undefined 用于局部按键映射表中,以覆盖全局按键
绑定并使该键在局部变为未定义状态。若将局部绑定设为
nil 则无法实现此效果,因为 nil 不会覆盖全局绑定。
如果找到任何其他类型的对象,至此在查找过程中使用的事件 构成了一个完整的键,该对象即为该键的绑定,但 此绑定无法作为命令执行。
简而言之,按键映射表条目可以是按键映射表、命令、键盘宏、
指向上述任一类型的符号,或 nil。
以下是与按键查找相关的函数与变量。
该函数返回 key 在 keymap 中的绑定定义。本章中所有其他用于查找按键的函数均基于
keymap-lookup 实现。示例如下:
(keymap-lookup (current-global-map) "C-x C-f")
⇒ find-file
(keymap-lookup (current-global-map) "C-x C-f 1 2 3 4 5")
⇒ 2
若字符串或向量 key 并非 keymap 中前缀按键所定义的有效按键序列,则说明该按键过长, 末尾存在不属于单个按键序列的多余事件。此时返回值为一个数字,表示 key 前端可构成完整按键的事件数量。
若 accept-defaults 为非 nil,keymap-lookup 会同时考虑默认绑定与 key
中具体事件的绑定;否则仅报告 key 对应序列的绑定,忽略默认绑定,除非显式指定(可在 key
中传入 t,详见 按键映射的格式)。
若 key 包含 Meta 字符(非功能键),该字符会被隐式转换为双字符序列:meta-prefix-char
的值后接对应的非 Meta 字符。因此下面第一个示例会被转换为第二个示例处理。
(keymap-lookup (current-global-map) "M-f")
⇒ forward-word
(keymap-lookup (current-global-map) "ESC f")
⇒ forward-word
参数 keymap 可为 nil,表示在当前生效的按键映射中查找 key(由 current-active-maps
返回,see 活跃按键映射表);也可以是单个按键映射或按键映射列表,表示仅在指定映射中查找。
与 read-key-sequence 不同,该函数不会以丢弃信息的方式修改指定事件(see 读取按键序列)。
具体而言,它不会将字母转为小写,也不会将拖拽事件改为点击事件。
与常规命令循环一致,keymap-lookup 会通过在当前按键映射中再次查找,对查找到的命令执行重映射。
但若可选第三个参数 no-remap 为非 nil,则直接返回原始命令而不进行重映射。
若可选参数 position 为非 nil,它指定一个由 event-start 与 event-end
返回的鼠标位置,此时查找将在该位置关联的按键映射中进行,而非 keymap。position
也可以是数字或标记,此时会被解释为缓冲区位置,函数将使用该位置而非光标处的按键映射属性。
用于在按键映射中取消按键的定义。该函数会调用 ding,但不会抛出错误。
该函数返回 key 在当前局部按键映射中的绑定,若未定义则返回 nil。
参数 accept-defaults 用于控制是否检查默认绑定,规则与 keymap-lookup(见上文)一致。
该函数返回 key 在当前全局按键映射中的绑定,若未定义则返回 nil。
参数 accept-defaults 用于控制是否检查默认绑定,规则与 keymap-lookup(见上文)一致。
该函数返回 key 所有生效的次要模式绑定构成的列表。更精确地说,返回由 (modename . binding)
组成的关联列表,其中 modename 是启用该次要模式的变量,binding 是 key 在该模式下的绑定。
若 key 无次要模式绑定,则返回 nil。
若找到的首个绑定并非前缀定义(按键映射或定义为按键映射的符号),则会忽略后续其他次要模式的绑定, 因其会被完全遮蔽。同理,列表也会忽略位于前缀绑定之后的非前缀绑定。
参数 accept-defaults 用于控制是否检查默认绑定,规则与 keymap-lookup(见上文)一致。
该变量为 Meta 前缀字符编码,用于将 Meta 字符转换为双字符序列,以便在按键映射中查找。 为获得可用结果,其值应设为前缀事件(see 前缀键)。默认值为 27,即 ESC 的 ASCII 编码。
只要 meta-prefix-char 保持为 27,按键查找就会将 M-b 转换为 ESC b,
该组合通常绑定为 backward-word 命令。但若将其设为 24(即 C-x 的编码),Emacs 会将
M-b 转换为 C-x b,其标准绑定为 switch-to-buffer 命令。(切勿实际执行此操作!)
示例如下:
meta-prefix-char ; The default value.
⇒ 27
(key-binding "\M-b")
⇒ backward-word
?\C-x ; The print representation ⇒ 24 ; of a character.
(setq meta-prefix-char 24)
⇒ 24
(key-binding "\M-b")
⇒ switch-to-buffer ; Now, typing M-b is
; like typing C-x b.
(setq meta-prefix-char 27) ; Avoid confusion!
⇒ 27 ; Restore the default value!
这种单事件转双事件的转换仅对字符生效,不适用于其他类型的输入事件。因此 M-F1 这类功能键 不会被转换为 ESC F1。
按键序列(key sequence)(简称按键(key))是由一个或多个输入事件构成的整体单元。输入事件包括字符、功能键、鼠标操作,或 Emacs 之外的系统事件,例如 iconify-frame(see 输入事件)。
Emacs Lisp 中按键序列的表示形式为字符串或向量。除非另有说明,所有接受按键序列作为参数的 Emacs Lisp 函数均可处理这两种表示形式。
在字符串表示形式中,字母与数字字符通常表示自身;例如 "a" 代表 a,
"2" 代表 2。控制字符事件以子串 "\C-" 为前缀,Meta 字符以
"\M-" 为前缀;例如 "\C-x" 代表按键 C-x。
此外,TAB、RET、ESC 和 DEL 事件分别由
"\t"、"\r"、"\e" 和 "\d" 表示。完整按键序列的字符串形式
是其各组成事件字符串形式的拼接;因此 "\C-xl" 代表按键序列 C-x l。
包含功能键、鼠标按键事件、系统事件,或非ASCII字符(如 C-= 或 H-a)的按键序列无法用字符串表示,必须使用向量表示。
在向量表示形式中,向量的每个元素以其 Lisp 形式表示一个输入事件。See 输入事件。
例如,向量 [?\C-x ?l] 代表按键序列 C-x l。
如需查看字符串与向量形式的按键序列示例,可参考 Init Rebinding in The GNU Emacs Manual。
该函数将文本 keyseq-text(字符串常量)转换为按键序列(字符串或向量常量)。
keyseq-text 的内容所使用的语法,与 C-x C-k RET(kmacro-edit-macro)
命令所打开的缓冲区中的语法一致;特别地,功能键名称必须用 ‘<…>’ 包裹。
See Edit Keyboard Macro in The GNU Emacs Manual。
(kbd "C-x") ⇒ "\C-x" (kbd "C-x C-f") ⇒ "\C-x\C-f" (kbd "C-x 4 C-f") ⇒ "\C-x4\C-f" (kbd "X") ⇒ "X" (kbd "RET") ⇒ "^M" (kbd "C-c SPC") ⇒ "\C-c " (kbd "<f1> SPC") ⇒ [f1 32] (kbd "C-M-<down>") ⇒ [C-M-down]
kbd 函数兼容性极强,即便所用语法不完全规范,也会尽量返回合理结果。
若要检查语法是否真正有效,可使用 key-valid-p 函数。
历史上,Emacs 支持多种不同的按键定义语法。如今文档推荐的按键绑定方式,是使用
key-valid-p 所支持的语法,这也是 keymap-set、keymap-lookup
等函数所支持的语法。本节介绍旧式语法与接口函数;新代码中不应使用这些内容。
define-key(以及其他用于重新绑定按键的底层函数)可识别多种按键语法。
可以使用一个由修饰键名称加一个基础事件(字符或功能键名称)组成的列表。
例如 [(control ?a) (meta b)] 等价于 C-a M-b,
[(hyper control left)] 等价于 C-H-left。
在内部,按键序列常使用针对 Shift、Control、Meta 修饰键的特殊转义序列表示为字符串(see 字符串类型),
用户在重新绑定按键时也可使用这种表示形式。像 "\M-x" 这样的字符串会被解析为单个 M-x,
"\C-f" 被解析为单个 C-f,而 "\M-\C-x" 与 "\C-\M-x"
均会被解析为单个 C-M-x。
这是按键序列的另一种内部表示形式。它比字符串形式支持更丰富的修饰键,同时也支持功能键。 例如 ‘[?\C-\H-x home]’ 代表按键序列 C-H-x home。 See 字符类型.
该函数与 keymap-set 类似(see 修改按键绑定),
但仅支持旧式按键语法。
此外,该函数还有一个 remove 参数。若其为非nil,则会移除该按键定义。
这与将定义设为 nil 效果基本相同,但在 keymap 存在父映射、且 key
遮蔽了父映射中同名绑定时会产生差异。使用 remove 时,后续查找会返回父映射中的绑定;
而设为 nil 定义时,查找会直接返回 nil。
以下是其他旧式按键定义函数与命令,并列出新代码中应替代使用的现代函数。
该函数将当前全局映射中 key 的绑定设为 binding。
请改用 keymap-global-set。
该函数从当前全局映射中移除 key 的绑定。
请改用 keymap-global-unset。
该函数将当前局部按键映射中 key 的绑定设为 binding。
请改用 keymap-local-set。
该函数从当前局部映射中移除 key 的绑定。
请改用 keymap-local-unset。
该函数将 keymap 中所有绑定到 olddef 的按键,替换为绑定到 newdef。
换言之,olddef 出现的所有位置都会被替换为 newdef。函数返回 nil。
请改用 keymap-substitute。
在 map 中为 key 定义值为 binding 的绑定,用法与 define-key 一致,
但会将该绑定放置在 map 中事件 after 的绑定之后。参数 key 长度应为 1—即仅含一个元素的向量或字符串。而 after 应为单个事件类型—符号或字符,而非序列。
新绑定会位于 after 绑定之后。若 after 为 t 或被省略,
则新绑定放在按键映射的最后面。不过,新绑定会添加在任何继承的按键映射之前。
请改用 keymap-set-after 替代此函数。
该函数修改 keyboard-translate-table,将字符编码 from 转换为字符编码 to。
如有必要,它会创建键盘转换表。请改用 key-translate。
该函数根据当前生效的按键映射返回 key 的绑定。若 key 在映射中未定义,结果为 nil。
参数 accept-defaults 控制是否检查默认绑定,规则与 lookup-key 一致(see 按键查找函数)。
若 no-remap 为非nil,key-binding 会忽略命令重映射(see 命令重映射),
直接返回为 key 指定的绑定。可选参数 position 应为缓冲区位置或类似 event-start
返回值的事件位置;它指定函数基于该位置查询对应的映射。
若 key 不是字符串或向量,Emacs 会抛出错误。
请改用 keymap-lookup 替代此函数。
该函数返回 key 在 keymap 中的定义。若字符串或向量 key 并非 keymap 中前缀按键所指定的有效按键序列,则说明其过长,末尾存在不属于单个按键序列的多余事件。 此时返回值为一个数字,表示 key 前端可构成完整按键的事件数量。
若 accept-defaults 为非nil,lookup-key 会同时考虑默认绑定与
key 中具体事件的绑定;否则仅报告 key 对应序列的绑定,忽略默认绑定,除非显式指定。
请改用 keymap-lookup 替代此函数。
该函数返回 key 在当前局部按键映射中的绑定,若未定义则返回 nil。
参数 accept-defaults 控制是否检查默认绑定,规则与 lookup-key(见上文)一致。
请改用 keymap-local-lookup 替代此函数。
该函数返回 key 在当前全局按键映射中的绑定,若未定义则返回 nil。
参数 accept-defaults 控制是否检查默认绑定,规则与 lookup-key(见上文)一致。
请改用 keymap-global-lookup 替代此函数。
该函数将由修饰键名称与基础事件类型组成的列表,转换为包含全部修饰信息的事件类型。 基础事件类型必须是列表的最后一个元素。例如:
(event-convert-list '(control ?a))
⇒ 1
(event-convert-list '(control meta ?a))
⇒ -134217727
(event-convert-list '(control super f1))
⇒ C-s-f1
一种特殊的键绑定可用于 重映射(remap) 一个命令
至另一个命令,而无需引用绑定到
原命令的键序列。要使用此功能,需为一个
以虚拟事件 remap 开头的键序列创建键绑定,
后跟你想要重映射的命令名;对于该绑定,
指定新的定义(通常为命令名,但也可以是键绑定的任何其他有效定义)。
例如,假设 My 模式提供了一个特殊命令
my-kill-line,该命令应当替代 kill-line
被调用。要实现这一点,其模式键盘映射应包含
如下重映射:
(keymap-set my-mode-map "<remap> <kill-line>" 'my-kill-line)
此后,每当 my-mode-map 处于激活状态时,若用户按下
C-k(kill-line默认的全局键序列),Emacs
将转而运行 my-kill-line。
注意,重映射仅通过激活的键盘映射生效;
例如,将重映射放入 ctl-x-map 这类前缀键盘映射
通常无效,因为此类映射本身并非激活状态。
此外,重映射仅生效于单一层级;在以下示例中,
(keymap-set my-mode-map "<remap> <kill-line>" 'my-kill-line) (keymap-set my-mode-map "<remap> <my-kill-line>" 'my-other-kill-line)
kill-line 并不会被重映射至 my-other-kill-line。
实际效果是,若普通键绑定指向 kill-line,
会被重映射为 my-kill-line;若普通绑定指向
my-kill-line,则会被重映射为 my-other-kill-line。
要撤销一个命令的重映射,可将其重映射至 nil,例如:
(keymap-set my-mode-map "<remap> <kill-line>" nil)
该函数返回当前激活键盘映射下,command (一个符号)
对应的重映射结果。若 command 未被重映射
(通常情况)或不是符号,函数返回 nil。
position 可用于指定缓冲区位置或事件位置,
以确定使用哪些键盘映射,用法与 key-binding相同。
若可选参数 keymaps 非 nil,
则指定一组待搜索的键盘映射列表。
若 position非 nil,此参数将被忽略。
当 read-key-sequence 函数读取键序列时
(see 读取按键序列),它会使用 翻译键盘映射(translation keymaps)
将某些事件序列翻译为其他序列。翻译键盘映射
按优先级依次为 input-decode-map、
local-function-key-map 和 key-translation-map。
翻译键盘映射的结构与其他键盘映射相同, 但用途不同:它们用于在读取键序列时执行翻译, 而非为完整键序列绑定命令。每读取一个键序列时, 都会对照各翻译键盘映射进行检查。若某翻译键盘映射 将 k 绑定至向量 v,则每当 k 作为子序列出现在键序列 任何位置时, 该子序列都会被替换为 v中的事件。
例如,VT100 终端在按下小键盘键 PF1 时
会发送 ESC O P。在这类终端上,
Emacs 必须将该事件序列翻译为单个事件 pf1。
这一过程通过在 input-decode-map 中
将 ESC O P 绑定至 [pf1] 实现。
因此,当你在终端上按下 C-c PF1 时,
终端会发出字符序列 C-c ESC O P,
而 read-key-sequence 会将其翻译回
C-c PF1,并以向量 [?\C-c pf1] 形式返回。
翻译键盘映射仅在 Emacs 完成键盘输入解码后生效
(通过 keyboard-coding-system 指定的输入编码系统)。
See Terminal I/O Encoding。
该变量保存一个键盘映射,用于描述普通字符终端上 功能键发送的字符序列。
input-decode-map 的值通常根据终端的
Terminfo 或 Termcap 条目自动设置,但有时
需要终端专用的 Lisp 文件补充配置。
Emacs 内置了许多常见终端的专用文件;
其主要作用是在 input-decode-map 中添加
Termcap 与 Terminfo 无法自动推导的条目。
See Terminal-Specific Initialization。
该变量保存一个与 input-decode-map 类似的键盘映射,
区别在于它描述的是应被翻译为更优替代方案的键序列。
其生效顺序在 input-decode-map 之后、
key-translation-map 之前。
若 local-function-key-map 中的条目
与次要模式、局部或全局键盘映射中的绑定冲突,
则该条目会被忽略。即,重映射仅在原键序列
原本无任何绑定时才生效。
local-function-key-map 继承自 function-key-map。
若希望绑定在所有终端生效,应修改后者;
因此几乎总是优先使用前者。
该变量是另一个用途与 input-decode-map 相似的键盘映射,
用于将输入事件翻译为其他事件。
与 input-decode-map 的区别在于,
它在 local-function-key-map 翻译完成后才生效,
接收其翻译后的结果。
与 input-decode-map 相同、但与 local-function-key-map 不同,
无论输入键序列是否存在普通绑定,该键盘映射都会生效。
但需注意,实际键绑定仍可能影响 key-translation-map,
即使其会被翻译映射覆盖。
实际上,实际键绑定会覆盖 local-function-key-map,
从而可能改变 key-translation-map接收的键序列。
显然,应尽量避免此类情况。
key-translation-map 的设计意图是供用户
将一个字符集映射至另一个,包括通常绑定到
self-insert-command 的普通字符。
除简单别名外,你还可以在 input-decode-map、
local-function-key-map 和 key-translation-map 中
使用函数而非键序列作为键的翻译结果。
此时该函数会被调用,以计算该键的翻译结果。
键翻译函数接收一个参数,即 read-key-sequence 中指定的提示;
若键序列由编辑器命令循环读取,则为 nil。
大多数情况下可忽略该提示值。
若该函数自身读取输入,可能会改变后续事件。 例如,以下代码定义 C-c h, 将其后跟随的字符转换为带 Hyper 修饰键的字符:
(defun hyperify (prompt)
(let ((e (read-event)))
(vector (if (numberp e)
(logior (ash 1 24) e)
(if (memq 'hyper (event-modifiers e))
e
(add-event-modifier "H-" e))))))
(defun add-event-modifier (string e)
(let ((symbol (if (symbolp e) e (car e))))
(setq symbol (intern (concat string
(symbol-name symbol))))
(if (symbolp e)
symbol
(cons symbol (cdr e)))))
(keymap-set local-function-key-map "C-c h" 'hyperify)
键翻译函数可能需要根据包含非键盘事件的键序列
中的事件参数调整行为(see 输入事件)。
该信息可从变量 current-key-remap-sequence 获取,
在调用键翻译函数时,该变量会绑定到正在翻译的键子序列。
键序列的结束判定条件为:该键序列已绑定到某个命令, 或 Emacs 判定后续无任何事件可使其成为有效绑定的序列。
这意味着,尽管 input-decode-map 和 key-translation-map
无论原键序列是否有绑定都会生效,但已有绑定仍可能导致翻译无法进行。
例如,回到前面的 VT100 示例,若为全局映射添加 C-c ESC 的绑定,
则当用户按下 C-c PF1 时,Emacs 无法将 C-c ESC O P
解码为 C-c PF1,因为它会在 C-c ESC 后立即停止读取按键,
将 O P 留待后续处理。这是为了应对用户确实按下 C-c ESC 的情况,
此时 Emacs 不应等待下一个按键来判断用户按下的是 ESC还是PF1。
因此,应避免将命令绑定到以翻译键序列前缀为结尾的键序列。 主要易出问题的后缀/前缀包括 ESC、 M-O(实际为 ESC O)和 M-[(实际为 ESC [)。
本节介绍一些便捷的交互式界面,用于修改按键绑定。
它们通过调用 keymap-set 实现(see 修改按键绑定)。
在交互式使用时,这些命令会提示输入参数 key,并要求用户输入合法的按键序列;
同时也会提示输入该按键序列的 binding,并要求输入一个命令名称
(即满足 commandp 的符号,see 交互式调用)。
当从 Lisp 代码中调用时,这些命令要求 key 是满足 key-valid-p 的字符串
(see 按键序列),而 binding 可以是按键映射中任何有意义的 Lisp 对象
(see 按键查找)。
用户常在初始化文件中使用 keymap-global-set 进行简单的自定义配置
(see The Init File)。例如:
(keymap-global-set "C-x C-\\" 'next-line)
会将 C-x C-\ 重新绑定为向下移动一行。
(keymap-global-set "M-<mouse-1>" 'mouse-set-point)
会将配合 Meta 键使用的第一个(最左侧)鼠标按键,重新绑定为在点击位置设置光标。
在 Lisp 代码中指定需要绑定的按键时,若使用非 ASCII 文本字符需格外谨慎。 如果这些字符按多字节文本读取(Lisp 文件中通常如此,see 加载非 ASCII 字符), 你也必须以多字节形式输入对应按键。例如,若你使用如下代码:
(keymap-global-set "ö" 'my-function) ; bind o-umlaut
且你的语言环境为多字节 Latin-1,这些命令实际绑定的是编码为 246 的多字节字符, 而非 Latin-1 终端发送的字节码 246(M-v)。 要使用该绑定,你需要通过合适的输入法让 Emacs 正确解码键盘输入 (see Input Methods in The GNU Emacs Manual)。
该函数在当前全局映射中将 key 的绑定设置为 binding。
(keymap-global-set key binding) ≡ (keymap-set (current-global-map) key binding)
该函数从当前全局映射中移除 key 的绑定。
该函数的一种用途是为定义更长的按键序列做准备,该序列以 key 作为前缀— 若 key 已有非前缀绑定,则不允许进行此类定义。例如:
(keymap-global-unset "C-l")
⇒ nil
(keymap-global-set "C-l C-l" 'redraw-display)
⇒ nil
该函数在当前局部按键映射中将 key 的绑定设置为 binding。
(keymap-local-set key binding) ≡ (keymap-set (current-local-map) key binding)
该函数从当前局部映射中移除 key 的绑定。
本节介绍用于遍历所有当前按键映射、以输出帮助信息的函数。
若要显示某个特定按键映射中的绑定关系,可以使用 describe-keymap 命令(see Other Help Commands in The GNU Emacs Manual)。
该函数返回所有可从 keymap(通过零个或多个前缀键)访问到的按键映射构成的列表。
返回值为一个关联表,元素格式为 (key . map),
其中 key 是一个前缀键,它在 keymap 中的定义即为 map。
该关联表中的元素按 key 长度递增排序。
第一个元素始终为 ([] . keymap),
因为指定的按键映射可通过不含任何事件的前缀访问到自身。
若指定了 prefix,它应当是一个前缀按键序列;
此时 accessible-keymaps 只包含前缀以 prefix 开头的子映射。
这些元素的形式与 (accessible-keymaps) 的返回值完全相同,唯一区别是省略了部分元素。
在下面的示例中,返回的关联表表明按键 ESC(显示为 ‘^[’)是一个前缀键,
其定义为稀疏按键映射 (keymap (83 . center-paragraph) (115 . foo))。
(accessible-keymaps (current-local-map))
⇒(([] keymap
(27 keymap ; Note this keymap for ESC is repeated below.
(83 . center-paragraph)
(115 . center-line))
(9 . tab-to-tab-stop))
("^[" keymap
(83 . center-paragraph)
(115 . foo)))
在下面的示例中,C-h 是一个前缀键,
它使用一个以 (keymap (118 . describe-variable)…) 开头的稀疏按键映射。
另一个前缀 C-x 4 使用的按键映射同时也是变量 ctl-x-4-map 的值。
事件 mode-line 是若干虚拟事件之一,用作窗口特定区域中鼠标操作的前缀。
(accessible-keymaps (current-global-map))
⇒ (([] keymap [set-mark-command beginning-of-line ...
delete-backward-char])
("^H" keymap (118 . describe-variable) ...
(8 . help-for-help))
("^X" keymap [x-flush-mouse-queue ...
backward-kill-sentence])
("^[" keymap [mark-sexp backward-sexp ...
backward-kill-word])
("^X4" keymap (15 . display-buffer) ...)
([mode-line] keymap
(S-mouse-2 . mouse-split-window-horizontally) ...))
以上并非实际中能看到的全部按键映射。
函数 map-keymap 会对 keymap 中的每一个绑定执行一次 function。
它传递两个参数:事件类型与绑定值。如果 keymap 存在父映射,
父映射中的绑定也会一并包含。该过程是递归的:若父映射自身还有父映射,则祖父映射的绑定也会被包含,依此类推。
该函数是遍历一个按键映射中所有绑定的最简洁方式。
该函数是 where-is 命令使用的子例程(see Help in The GNU Emacs Manual)。
它返回一组按键映射中所有绑定到 command 的按键序列(任意长度)构成的列表。
参数 command 可以是任意对象;
函数会使用 eq 与所有按键映射条目进行比较。
若 keymap 为 nil,则使用当前活跃的按键映射,
忽略 overriding-local-map(即假设其值为 nil)。
若 keymap 是一个按键映射,则搜索范围为 keymap 与全局按键映射。
若 keymap 是按键映射列表,则只搜索这些映射。
通常最适合将 overriding-local-map 作为 keymap 的参数表达式。
此时 where-is-internal 会精确搜索当前活跃的按键映射。
若只想搜索全局映射,可传入 (keymap)(空按键映射)作为 keymap。
若 firstonly 为 non-ascii,则返回值为单个向量,
表示找到的第一个按键序列,而非所有可能序列构成的列表。
若 firstonly 为 t,则返回第一个按键序列,
但优先选择完全由 ASCII 字符(或带 Meta 修饰的 ASCII 字符)组成的序列,
且返回值绝不会是菜单绑定。
若 noindirect 非 nil,where-is-internal 不会深入菜单项内部查找其绑定的命令。这使得可以直接搜索菜单项本身。
第五个参数 no-remap 决定函数如何处理命令重映射(see 命令重映射)。主要有两种情况:
若 no-remap 为 nil,则查找 other-command 的绑定并将其视作 command 的绑定。
若 no-remap 非 nil,则在可能的按键序列列表中包含向量 [remap other-command],而非查找这些绑定。
若 no-remap 为 nil,则返回 other-command 的绑定而非 command。
若 no-remap 非 nil,则返回 command 本身的绑定,忽略其被重映射的事实。
若某个命令绑定到类似 [some-event] 的按键,
且 some-event 的符号属性列表中包含非 nil 的 non-key-event 属性,则该绑定会被 where-is-internal 忽略。
该函数生成所有当前按键绑定的列表,并在名为 *Help* 的缓冲区中显示。 文本按模式分组:首先是次要模式,随后是主模式,最后是全局绑定。
若 prefix 非 nil,它应当是一个前缀键;此时列表只包含以 prefix 开头的按键。
当多个 ASCII 连续编码的字符具有相同定义时,
会合并显示为 ‘firstchar..lastchar’。
这种情况下需要知道 ASCII 编码才能确定具体字符。
例如,在默认全局映射中,字符 ‘SPC .. ~’ 由一行统一描述。
SPC 的 ASCII 码为 32,~ 为 126,其间包含所有常规可打印字符(如字母、数字、标点等);
所有这些字符均绑定到 self-insert-command。
若 buffer-or-name 非 nil,它应当是一个缓冲区或缓冲区名称。
此时 describe-bindings 会列出该缓冲区的绑定,而非当前缓冲区的绑定。
按键映射既可以作为菜单使用,也可以为键盘按键和鼠标按钮定义绑定。 菜单通常通过鼠标触发,但也可以通过键盘操作。 如果菜单按键映射对下一个输入事件处于活跃状态,就会激活键盘菜单功能。
如果一个按键映射带有整体提示字符串(overall prompt string)(该字符串作为按键映射的一个元素), 它就可以作为菜单使用。(See 按键映射的格式.) 该字符串应描述菜单中命令的用途。 根据显示菜单所使用的工具集(如果有),Emacs 会在某些情况下将整体提示字符串作为菜单标题显示。19 键盘菜单也会显示该整体提示字符串。
创建带有提示字符串的按键映射最简单的方法是,
在调用 make-keymap、make-sparse-keymap (see 创建按键映射) 或
define-prefix-command (see Definition of define-prefix-command) 时,
将该字符串作为参数传入。如果你不希望该按键映射用作菜单,则不要为其指定提示字符串。
该函数返回 keymap 的整体提示字符串,如果没有则返回 nil。
菜单项就是按键映射中的绑定。每个绑定将一个事件类型关联到一个定义, 但事件类型对菜单外观没有影响。(我们通常使用伪事件—即键盘无法生成的符号—作为菜单项绑定的事件类型。)菜单完全根据按键映射中这些事件对应的绑定生成。
菜单项的顺序与按键映射中绑定的顺序一致。由于 define-key 会将新绑定放在前面,
如果你在意顺序,应该从菜单底部向上依次定义菜单项。
向已有菜单添加项时,可以使用 keymap-set-after 指定其在菜单中的位置。(see 修改菜单)
定义菜单项更简单(也是最初)的方式,是将某种事件类型(具体事件类型无关紧要)绑定为如下形式:
(item-string . real-binding)
其中 CAR 部分 item-string 是在菜单中显示的字符串。 它应当简短—最好一到三个词,并描述其所对应命令的功能。 注意并非所有图形工具集都能在菜单中显示非ASCII文本(键盘菜单可以正常显示,GTK+ 工具集也基本支持)。
你也可以额外提供第二个字符串,称为帮助提示字符串,写法如下:
(item-string help . real-binding)
help 指定了当鼠标悬停在该项上时显示的帮助提示字符串,其显示方式与 help-echo 文本属性相同(see Help display)。
对 define-key 而言,item-string 和 help-string 属于事件绑定的一部分。
但 lookup-key 只返回 real-binding,且执行按键时也只使用 real-binding。
如果 real-binding 为 nil,则 item-string 会出现在菜单中,但无法被选中。
如果 real-binding 是一个符号,并且拥有非 nil 的 menu-enable 属性,
则该属性是一个表达式,用于控制菜单项是否可用。
每次使用该按键映射显示菜单时,Emacs 都会求值该表达式,仅当结果非 nil 时才启用该菜单项。
菜单项被禁用时会以模糊样式显示,且无法选中。
菜单栏并不会在每次查看菜单时重新计算哪些项可用。
这是因为 X 工具集需要预先获得完整的菜单树形结构。
若要强制刷新菜单栏的可用状态,可调用 force-mode-line-update(see 模式行格式)。
扩展格式的菜单项相比简单格式更灵活、更清晰。定义事件绑定时,使用以符号 menu-item 开头的列表即可。对于不可选中的纯文本项,绑定形式如下:
(menu-item item-name)
以两个或更多短横线开头的字符串表示分隔线,详见 菜单分隔线。
若要定义可选中的实际菜单项,扩展格式绑定写法如下:
(menu-item item-name real-binding
. item-property-list)
其中 item-name 是一个表达式,求值结果为菜单项显示字符串。因此该字符串不必是常量。
第三个元素 real-binding 可以是要执行的命令(此时为普通菜单项);
也可以是一个按键映射,这会生成子菜单,而 item-name 作为子菜单名称;
最后还可以是 nil,表示不可选中的菜单项,这在生成分隔线等场景时非常有用。
列表尾部的 item-property-list 为属性列表格式(see 属性列表),用于存放其他信息。
以下是支持的属性列表:
:enable form对 form 求值的结果决定该项是否可用(非 nil 表示可用)。不可用时无法点击选中。
:visible form对 form 求值的结果决定该项是否在菜单中显示(非 nil 表示显示)。不显示时,菜单效果如同该项未定义。
:help help该属性值 help 指定鼠标悬停时显示的帮助提示字符串,
显示方式与 help-echo 文本属性相同(see Help display)。
注意该字符串必须是常量,这一点与文本和覆盖物的 help-echo 属性不同。
:button (type . selected)该属性用于定义单选按钮和复选按钮。CAR 部分 type 为类型,
取值为 :toggle 或 :radio。
CDR 部分 selected 是一个表达式,求值结果表示该按钮当前是否被选中。
复选按钮(toggle) 是一种根据 selected 值显示开启/关闭状态的菜单项。
命令本身应切换该状态:为 nil 时设为 t,为 t 时设为 nil。下面是切换 debug-on-error 标志的菜单项定义示例:
(menu-item "Debug on Error" toggle-debug-on-error
:button (:toggle
. (and (boundp 'debug-on-error)
debug-on-error)))
该写法有效是因为 toggle-debug-on-error 被定义为切换变量 debug-on-error 的命令。
单选按钮(Radio buttons) 是一组菜单项,任何时刻仅有一项被选中。 通常由一个变量记录当前选中项。组内每个单选按钮的 selected 表达式用于判断变量是否为对应选中值。 点击按钮应修改变量,使当前点击项变为选中状态。
:key-sequence key-sequence该属性指定作为键盘等价快捷键显示的按键序列。
Emacs 在菜单中显示 key-sequence 前会验证其确实与该菜单项等价,
因此只有正确的按键序列才会生效。将 key-sequence 设为 nil 等同于不使用该属性。
:keys string该属性直接指定 string 作为菜单项的快捷键提示字符串。 可在 string 中使用 ‘\\[...]’ 文档结构。
该属性也可以是一个无参函数,执行后返回字符串。菜单每次刷新时都会调用该函数,因此不应使用耗时较长的函数,且需保证可在任意上下文安全调用。
:filter filter-fn该属性支持动态计算菜单项绑定。属性值 filter-fn 为单参数函数,调用时参数为 real-binding,函数应返回实际使用的绑定。
Emacs 可能在任意重绘或操作菜单数据结构时调用该函数,因此需保证其可随时安全执行。
:wrap wrap-p若在工具栏中 wrap-p 非 nil,则该菜单项不显示,并使后续项换行显示。GTK+ 或 Nextstep 工具集不支持该属性。
菜单分隔线是一类不显示任何文本的菜单项,它通过一条水平线将菜单划分为多个区域。 分隔线在菜单按键映射中的写法如下:
(menu-item separator-type)
其中 separator-type 是以两个或更多短横线开头的字符串。
最简单的情况下,separator-type 仅由短横线组成,表示使用默认样式的分隔线。
(为兼容起见,"" 和 "-" 也会被视为分隔线。)
separator-type 取其他特定值时可以指定不同样式的分隔线, 可用样式如下表所示:
"--no-line""--space"仅增加垂直空白间距,不显示实际线条。
"--single-line"使用菜单前景色绘制的单实线。
"--double-line"使用菜单前景色绘制的双实线。
"--single-dashed-line"使用菜单前景色绘制的单虚线。
"--double-dashed-line"使用菜单前景色绘制的双虚线。
"--shadow-etched-in"呈现 3D 凹陷效果的单实线,这是仅使用纯短横线时的默认样式。
"--shadow-etched-out"呈现 3D 凸起效果的单实线。
"--shadow-etched-in-dash"呈现 3D 凹陷效果的单虚线。
"--shadow-etched-out-dash"呈现 3D 凸起效果的单虚线。
"--shadow-double-etched-in"呈现 3D 凹陷效果的双实线。
"--shadow-double-etched-out"呈现 3D 凸起效果的双实线。
"--shadow-double-etched-in-dash"呈现 3D 凹陷效果的双虚线。
"--shadow-double-etched-out-dash"呈现 3D 凸起效果的双虚线。
你也可以使用另一种命名风格:在双横线后加冒号,并将每个短横线替换为后续单词首字母大写。
例如 "--:singleLine" 等价于 "--single-line"。
可以使用更长的格式为分隔线指定 :enable、:visible 等属性:
(menu-item separator-type nil . item-property-list)
示例:
(menu-item "--" nil :visible (boundp 'foo))
部分系统和显示工具集并不完全支持以上所有分隔线类型。 若使用了不被支持的类型,菜单会显示一种与之相近且受支持的分隔线样式。
有时创建使用相同命令、但启用条件不同的菜单项是很有用的。
目前在 Emacs 中实现此功能的最佳方式是使用扩展菜单项;
在该特性出现之前,可以通过定义别名命令并在菜单项中使用它们来实现。
下面是一个示例,为 read-only-mode 创建两个别名,并为它们设置不同的启用条件:
(defalias 'make-read-only 'read-only-mode) (put 'make-read-only 'menu-enable '(not buffer-read-only)) (defalias 'make-writable 'read-only-mode) (put 'make-writable 'menu-enable 'buffer-read-only)
在菜单中使用别名时,通常需要显示真实命令名称对应的等效按键绑定,
而非别名本身(别名通常除菜单外一般不会绑定任何按键)。
若要实现此效果,可为别名符号设置一个非 nil 的
menu-alias 属性。如下所示:
(put 'make-read-only 'menu-alias t) (put 'make-writable 'menu-alias t)
这样会使 make-read-only 与 make-writable 对应的菜单项
显示 read-only-mode 的键盘绑定。
让菜单映射生成菜单的常规方式,是将其设为某个前缀键的定义。 (Lisp 程序可以显式弹出菜单并接收用户的选择—参见 Pop-Up Menus。)
若前缀键以鼠标事件结尾,Emacs 会通过弹出一个可见菜单来处理该菜单映射, 用户即可使用鼠标选择菜单项。当用户点击某个菜单项时, 所生成的事件即为绑定到该菜单项的字符或符号。 (若菜单包含多级结构或来自菜单栏,一个菜单项可能会生成一系列事件。)
通常推荐使用按键按下事件来触发菜单。 用户随后可通过释放按键来选定菜单项。
若菜单映射中包含对嵌套映射的绑定,则该嵌套映射对应一个 submenu(子菜单)。 此时会出现一个以嵌套映射的项字符串为标签的菜单项, 点击该项会自动弹出指定的子菜单。作为特例, 如果菜单映射中仅包含一个嵌套映射而无其他菜单项, 菜单会直接显示嵌套映射的内容,而非以子菜单形式呈现。
但是,若 Emacs 编译时未启用 X 工具集支持,或是在文本终端环境下, 子菜单将不受支持。每个嵌套映射都会显示为一个菜单项, 但点击后不会自动弹出子菜单。若希望模拟子菜单效果, 可在嵌套映射的项字符串开头添加 ‘@’。 这会使 Emacs 使用独立的 menu pane(菜单面板)显示该嵌套映射; 项字符串中 ‘@’ 之后的部分即为面板标签。 若 Emacs 未启用 X 工具集支持,或菜单在文本终端中显示, 则不会使用菜单面板;此时项字符串开头的 ‘@’ 在显示菜单标签时会被忽略,且不产生其他效果。
当一个以键盘事件(字符或功能键)结尾的前缀键,其定义为一个菜单按键映射时, 该按键映射将作为键盘菜单运行;用户通过键盘选择菜单项来指定下一个事件。
Emacs 会在回显区显示键盘菜单,先显示该映射的整体提示字符串,
随后依次列出各个选项(即该映射中绑定的项字符串)。
如果所有绑定无法一次性全部显示,用户可以按下 SPC 查看下一行选项。
连续按下 SPC 最终会到达菜单末尾,之后再循环回到开头。
(变量 menu-prompt-more-char 指定用于此功能的字符;
默认是 SPC。)
当用户在菜单中找到所需选项后,只需输入对应的字符— 即绑定到该选项的那个字符。
该变量指定用于请求显示菜单下一行的字符。其初始值为 32, 即 SPC 的字符编码。
下面是一个定义菜单按键映射的完整示例。 它对应菜单栏中 ‘Edit’ 菜单下的 ‘Replace’ 子菜单, 并且使用了扩展菜单项格式(see 扩展菜单项)。 首先我们创建按键映射,并为其命名:
(defvar menu-bar-replace-menu (make-sparse-keymap "Replace"))
接下来定义菜单项:
(define-key menu-bar-replace-menu [tags-repl-continue]
'(menu-item "Continue Replace" multifile-continue
:help "Continue last tags replace operation"))
(define-key menu-bar-replace-menu [tags-repl]
'(menu-item "Replace in tagged files" tags-query-replace
:help "Interactively replace a regexp in all tagged files"))
(define-key menu-bar-replace-menu [separator-replace-tags]
'(menu-item "--"))
;; ...
注意这些绑定所使用的符号;它们出现在被定义的按键序列中的方括号内。
在某些情况下,该符号与命令名称相同;有时则不同。
这些符号被当作功能键处理,但它们并不是键盘上真实的功能键。
它们不影响菜单本身的运行,但当用户从菜单中选择时会在回显区回显,
并且会出现在 where-is 与 apropos 的输出中。
本例中的菜单面向鼠标使用。如果一个菜单面向键盘操作, 即它被绑定到以键盘事件结尾的按键序列, 那么菜单项应当绑定到可通过键盘输入的字符或真实功能键。
定义为 ("--") 的绑定是一条分隔线。
与普通菜单项一样,分隔线也拥有一个按键符号,
本例中为 separator-replace-tags。
如果一个菜单包含两条分隔线,它们必须使用不同的按键符号。
下面代码将该菜单作为一项加入到父菜单中:
(define-key menu-bar-edit-menu [replace] (list 'menu-item "Replace" menu-bar-replace-menu))
注意这里直接使用了子菜单按键映射(即变量 menu-bar-replace-menu 的值),
而非符号 menu-bar-replace-menu 本身。
在父菜单项中使用该符号是没有意义的,
因为 menu-bar-replace-menu 并不是一个命令。
如果你希望将同一个替换菜单绑定到鼠标点击事件,可以这样做:
(define-key global-map [C-S-down-mouse-1] menu-bar-replace-menu)
Emacs 通常会在每个框架顶部显示一个 菜单栏(menu bar)。 See Menu Bars in The GNU Emacs Manual。 菜单项是虚拟功能键 MENU-BAR 的子命令,由当前生效的按键映射定义。
若要向菜单栏添加一项,可自行定义一个虚拟功能键(记作 key),
并为按键序列 [menu-bar key] 创建绑定。
最常见的做法是将该绑定设为一个菜单按键映射,
这样点击菜单栏该项即可打开下级菜单。
当多个生效的按键映射为菜单栏定义了同一个功能键时, 该菜单项只会出现一次。用户点击该菜单项后, 会弹出一个合并后的单一菜单,包含该项的所有子命令— 全局子命令、局部子命令以及次要模式子命令。
在计算菜单栏内容时,通常会忽略变量 overriding-local-map。
也就是说,菜单栏是按照 overriding-local-map 为 nil
时本应生效的按键映射计算得出的。See 活跃按键映射表。
下面是设置菜单栏项的示例:
;; 创建一个菜单按键映射(附带提示字符串) ;; 并将其设为菜单栏项的定义。 (define-key global-map [menu-bar words] (cons "Words" (make-sparse-keymap "Words")))
;; 在该菜单中定义具体子命令。
(define-key global-map
[menu-bar words forward]
'("Forward word" . forward-word))
(define-key global-map
[menu-bar words backward]
'("Backward word" . backward-word))
局部按键映射可以通过将同一个虚拟功能键重新绑定为 undefined
来取消全局按键映射创建的菜单栏项。
例如,Dired 模式就是这样隐藏 ‘Edit’ 菜单项的:
(define-key dired-mode-map [menu-bar edit] 'undefined)
此处 edit 是一个虚拟功能键对应的符号,
全局映射用它表示 ‘Edit’ 菜单项。
隐藏全局菜单项的主要目的,是为模式专属项腾出空间。
默认情况下,菜单栏先显示全局项,再显示局部映射定义的项。
该变量保存一组虚拟功能键列表,
用于指定哪些项显示在菜单栏末尾,而非按常规顺序排列。
默认值为 (help-menu),
因此 ‘Help’ 菜单项通常出现在菜单栏最后,位于局部菜单项之后。
这是一个常规钩子,在重绘菜单栏前由重绘机制运行,用于更新菜单栏内容。 你可以用它更新内容需要动态变化的菜单。 由于该钩子会被频繁调用,建议确保其调用的函数在常规情况下耗时很短。
在每个菜单栏项旁边,Emacs 会显示执行相同命令的按键绑定(若存在)。
这为不熟悉按键的用户提供了便捷提示。
若一个命令存在多个绑定,Emacs 通常显示找到的第一个绑定。
你可以为命令设置 :advertised-binding 符号属性,
指定要显示的特定按键绑定。See 文档中的按键绑定替换。
工具栏(tool bar)是位于框架顶部、菜单栏正下方的一行可点击图标。 See Tool Bars in The GNU Emacs Manual。 在图形界面下,Emacs 默认显示工具栏。
在每个框架中,框架参数 tool-bar-lines 控制为工具栏预留的行数高度。
值为 0 时隐藏工具栏。若该值非零且 auto-resize-tool-bars 非 nil,
工具栏会根据内容自动伸缩高度。若值为 grow-only,
工具栏仅自动扩展,不自动收缩。
工具栏内容由绑定到虚拟功能键 TOOL-BAR 的菜单按键映射控制
(与菜单栏的控制方式类似)。
因此你可以使用 define-key 定义工具栏项,写法如下:
(define-key global-map [tool-bar key] item)
其中 key 是用于区分不同项的虚拟功能键, item 是菜单项按键绑定(see 扩展菜单项), 用于指定该项的显示方式与行为。
常用的菜单映射项属性 :visible、:enable、:button
和 :filter 在工具栏绑定中同样有效,语义保持不变。
项中的 real-binding 必须是命令,而非按键映射;
换言之,不能将工具栏图标定义为前缀键。
:help 属性指定鼠标悬停时显示的提示字符串,
其显示方式与 help-echo 文本属性相同(see Help display)。
此外,你应当使用 :image 属性指定工具栏中显示的图像:
:image imageimage 可以是单个图像描述(see Images), 也可以是包含四个图像描述的向量。 若使用四元素向量,Emacs 会根据状态选择其中一个:
项启用且被选中时使用。
项启用但未被选中时使用。
项禁用且被选中时使用。
项禁用且未被选中时使用。
基于 GTK+ 和 NS 版本的 Emacs 会忽略第 1–3 项, 因为禁用与未选中状态的图像会从第 0 项自动生成。
若 image 是单个图像描述, Emacs 会对图像应用边缘检测算法,绘制禁用状态的工具栏按钮。
:rtl 属性指定用于从右到左书写语言的替代图像。
目前仅 GTK+ 版本的 Emacs 支持该属性。
部分工具库会在工具栏同时显示图像与文本。
若希望强制只显示图像,可将 :vert-only 属性设为非 nil。
与菜单栏类似,工具栏也支持分隔线(see 菜单分隔线)。
不过工具栏分隔线是垂直方向的,且仅支持一种样式。
它们在工具栏映射中以 (menu-item "--") 条目表示;
工具栏分隔线不支持 :visible 等属性。
在 GTK+ 和 Nextstep 工具栏中,分隔线由系统原生绘制;
其他环境下则使用竖线图像绘制。
默认工具栏的定义规则为:
若某个主模式的命令符号拥有 mode-class 属性且值为 special,
则不显示与编辑相关的默认工具栏项(see 主模式编码规范)。
主模式可以在局部映射中绑定 [tool-bar foo],
向全局工具栏添加项。
由于工具栏空间有限,部分主模式完全替换默认工具栏项是合理的;
默认绑定通过 tool-bar-map 间接实现,方便替换。
默认情况下,全局映射对 [tool-bar] 的绑定如下:
(keymap-global-set "<tool-bar>"
`(menu-item ,(purecopy "tool bar") ignore
:filter tool-bar-make-keymap))
函数 tool-bar-make-keymap 会根据变量 tool-bar-map 的值
动态生成实际的工具栏映射。
因此,你通常应通过修改该映射来调整默认(全局)工具栏。
Info 模式等部分主模式会将 tool-bar-map 设为缓冲区局部变量,
并赋值为其他映射,从而完全替换全局工具栏。
Emacs 提供三个便捷函数用于定义工具栏项,如下所示。
该函数通过修改 tool-bar-map 向工具栏添加一项。
icon 为图像基名,对应 XPM、XBM 或 PBM 格式文件,
由 find-image 查找。例如传入 ‘"exit"’,
彩色显示器上会按顺序查找 exit.xpm、exit.pbm、exit.xbm。
单色显示器上查找顺序为 ‘.pbm’、‘.xbm’、‘.xpm’。
def 为绑定的命令,key 为前缀映射中的虚拟功能键符号。
剩余参数 props 为添加到菜单项描述中的附加属性列表。
若要在局部映射中定义项,可在调用该函数时用 let 绑定 tool-bar-map:
(defvar foo-tool-bar-map
(let ((tool-bar-map (make-sparse-keymap)))
(tool-bar-add-item ...)
...
tool-bar-map))
该函数用于便捷定义与现有菜单栏绑定一致的工具栏项。
它会在 map(默认为 global-map)的菜单栏中查找 command 的绑定,
并为其添加 icon 对应的图像描述(查找规则同 tool-bar-add-item)。
生成的绑定会放入 tool-bar-map,因此该函数仅用于全局工具栏项。
map 必须包含绑定到 [menu-bar] 的有效映射。
剩余参数 props 为添加到菜单项描述中的附加属性。
该函数用于定义非全局的工具栏项。
用法与 tool-bar-add-item-from-menu 类似,
区别在于 in-map 指定要在其中创建定义的局部映射。
参数 from-map 对应 tool-bar-add-item-from-menu 的 map。
除了 tool-bar-map 中定义的工具栏项,
Emacs 还支持在按键映射 secondary-tool-bar-map 中指定额外一行 “次级(secondary”)” 工具栏项。
若工具栏位于框架顶部,这些项通常显示在主工具栏下方;
若工具栏位于底部,则显示在主工具栏上方(see Layout Parameters)。
若工具栏位于框架左侧或右侧,则不显示次级项。
若该变量非 nil,工具栏会自动调整大小以显示所有定义的项,
但高度不超过框架高度的四分之一。
若值为 grow-only,工具栏仅自动扩展,不自动收缩。
用户需输入 C-l 重绘框架,才能使工具栏收缩。
若 Emacs 使用 GTK+ 或 Nextstep 编译,工具栏仅支持单行显示, 该变量无效。
若该变量非 nil,鼠标悬停时工具栏项会呈现凸起效果。
该变量指定工具栏项周围的额外边距,单位为像素,默认值为 4。
该变量指定工具栏项的阴影宽度,单位为像素,默认值为 1。
该变量指定工具栏区域下方绘制的边框高度,为整数像素值。
若值为 internal-border-width(默认)或 border-width,
工具栏边框高度对应相应的框架参数。
你可以为按住 Shift、Control、Meta 等修饰键点击工具栏项定义特殊行为。 方法是通过虚拟功能键为原项创建关联的附加项。 具体来说,附加项应使用原项同名虚拟功能键的修饰版本。
例如,原项定义如下:
(define-key global-map [tool-bar shell]
'(menu-item "Shell" shell
:image (image :type xpm :file "shell.xpm")))
则可如下定义按住 Shift 键点击同一图标时的行为:
(define-key global-map [tool-bar S-shell] 'some-command)
有关为功能键添加修饰键的更多信息,参见 See 功能键。
若你有函数会动态修改工具栏项的启用/禁用状态,
界面上不一定会立即刷新。
若要强制重新计算工具栏,可调用 force-mode-line-update(see 模式行格式)。
当你在已有菜单中插入新项时,通常希望将其放在现有菜单项中的特定位置。
如果使用 define-key 添加项,它默认会出现在菜单最前面。
若要放在其他位置,可使用 keymap-set-after:
在 map 中为 key 定义值为 binding 的绑定,
用法与 keymap-set 类似(see 修改按键绑定),
但会将该绑定放置在事件 after 对应绑定的后面。
参数 key 应表示单个菜单项或按键,且满足 key-valid-p(see 按键序列)。
after 应为单个事件类型—符号或字符,而非序列。
新绑定会放在 after 绑定之后。
若 after 为 t 或被省略,则新绑定放在按键映射的最后面。
不过,新绑定会添加在任何继承映射之前。
示例如下:
(keymap-set-after my-menu "<drink>"
'("Drink" . drink-command) 'eat)
为虚拟功能键 DRINK 创建绑定,并将其放在 EAT 绑定的紧后方。
下面代码演示如何在 Shell 模式的 ‘Signals’ 菜单中,
在 break 项之后插入名为 ‘Work’ 的项:
(keymap-set-after shell-mode-map "<menu-bar> <signals> <work>"
'("Work" . work-command) 'break)
下列宏提供了一种便捷方式,用于定义弹出菜单和/或菜单栏菜单。
该宏定义一个弹出菜单和/或菜单栏子菜单,内容由 menu 指定。
若 symbol 非 nil,则它应为一个符号;
此时该宏会将 symbol 定义为用于弹出菜单的函数(see Pop-Up Menus),
并以 doc 作为其文档字符串。
它同时会将 symbol 定义为变量,其值为该菜单。
symbol 不需要加引号。
无论 symbol 取值如何,若 maps 是一个按键映射, 该菜单会被添加到该映射中,作为菜单栏的顶层菜单(see 菜单栏)。 maps 也可以是一个按键映射列表,此时菜单会被分别添加到每个映射中。
menu 的第一个元素必须是字符串,作为菜单标签。 其后可以跟随任意数量的下列关键字-参数对:
:filter functionfunction 必须是一个函数,当以一个参数(其他菜单项的列表)调用时, 返回菜单中实际要显示的项。
:visible includeinclude 是一个表达式;若其求值为 nil,则菜单设为不可见。
:included 是 :visible 的别名。
:active enableenable 是一个表达式;若其求值为 nil,则菜单不可选中。
:enable 是 :active 的别名。
menu 中剩余的元素为菜单项。
一个菜单项可以是包含三个元素的向量:[name callback enable]。
name 是菜单项名称(字符串)。
callback 是选中该项时运行的命令或要执行的表达式。
enable 是一个表达式;若求值为 nil,该项禁用不可选。
此外,菜单项也可以采用如下形式:
[ name callback [ keyword arg ]... ]
其中 name 和 callback 含义同上, 每个可选的 keyword 和 arg 对为下列之一:
:keys keyskeys 是一个字符串,作为菜单项的键盘等效键显示。
通常不需要此项,因为等效键会自动计算。
keys 在显示前会通过 substitute-command-keys 展开(see 文档中的按键绑定替换)。
:key-sequence keyskeys 用于提示显示哪个按键序列作为等效键, 适用于命令绑定了多个按键序列的情况。 若 keys 未绑定到与该菜单项相同的命令,则无效果。
:active enableenable 是一个表达式;若求值为 nil,该项设为不可选。
:enable 是 :active 的别名。
:visible includeinclude 是一个表达式;若求值为 nil,该项设为不可见。
:included 是 :visible 的别名。
:label formform 是一个表达式,求值后结果作为菜单项标签(默认为 name)。
:suffix formform 是一个动态求值的表达式,其结果会拼接到菜单项标签后。
:style stylestyle 是描述菜单项类型的符号;
可以是 toggle(复选框)、radio(单选按钮),
或其他值(表示普通菜单项)。
:selected selectedselected 是一个表达式;
当表达式值非 nil 时,复选框或单选按钮为选中状态。
:help helphelp 是描述该菜单项的字符串。
菜单项也可以是一个字符串,此时该字符串会以不可选文本形式显示在菜单中。 由短横线组成的字符串会显示为分隔线(see 菜单分隔线)。
菜单项还可以是一个格式与 menu 相同的列表,表示子菜单。
下面是使用 easy-menu-define 定义菜单的示例,
效果与 菜单栏 中的示例菜单类似:
(easy-menu-define words-menu global-map
"Menu for word navigation commands."
'("Words"
["Forward word" forward-word]
["Backward word" backward-word]))
模式(mode) 是一组用于定制 Emacs 行为的定义,可提供实用功能。模式分为两类:次模式(minor modes),这类模式提供的功能可在编辑时由用户开启或关闭;以及 主模式(major modes),用于编辑或交互特定类型的文本。每个缓冲区在同一时刻有且仅有一个 主模式(major modes)。
本章介绍如何编写主模式与次模式、如何在模式行中显示它们,以及它们如何运行用户提供的钩子。相关主题如键盘映射与语法表,请参见 按键映射 和 Syntax Tables。
钩子是一种变量,可用于存储一个或多个函数(see 什么是函数?), 使其在现有程序的特定时机被调用。Emacs 提供钩子机制以便用户进行定制。 钩子通常在初始化文件中设置(see The Init File),Lisp 程序也可以对其进行设置。 部分标准钩子变量的列表,See Standard Hooks。
Emacs 中的绝大多数钩子都是标准钩子。这类变量保存的是无参数调用的函数列表。 按照惯例,钩子名称以‘-hook’ 结尾即表示它是标准钩子。 我们尽可能将所有钩子设计为标准钩子,以便你可以用统一的方式使用它们。
每个主模式命令都会在初始化的最后阶段运行一个名为模式钩子(mode hook)的标准钩子。
这样用户就可以方便地定制该模式的行为,例如覆盖模式已经设置的缓冲区局部变量。
大多数次模式函数在执行完毕时也会运行对应的模式钩子。
不过钩子也用于其他场景,比如suspend-hook 钩子会在 Emacs 即将挂起之前运行(see Suspending Emacs)。
如果钩子变量名称不以‘-hook’ 结尾,则它通常是非标准钩子(abnormal hook)。 这类钩子与标准钩子有两点区别:调用时可以带有一个或多个参数,并且函数的返回值可能会被程序使用。 钩子的文档字符串会说明函数的调用方式以及返回值的用途。 添加到非标准钩子中的函数必须遵循该钩子规定的调用规范。 按照惯例,非标准钩子名称以‘-functions’ 结尾。
如果变量名称以‘-predicate’ 或单数形式的‘-function’ 结尾,则其值必须是单个函数,而不是函数列表。 与非标准钩子类似,这类单函数钩子对参数和返回值的要求各不相同,具体细节在各个变量的文档字符串中说明。
由于钩子(包括多函数钩子和单函数钩子)本质是变量,可以使用setq 修改其值,或使用let 临时绑定。
但更常见的需求是在保留钩子已有其他函数的前提下,添加或移除某个特定函数。
对于多函数钩子,推荐使用add-hook 和remove-hook 实现(see 设置钩子)。
大多数标准钩子变量初始为空,add-hook 可以正确处理这种情况。
使用add-hook 既可以全局添加钩子,也可以针对某个缓冲区局部添加。
对于仅保存单个函数的钩子,则不适合使用add-hook,可以使用add-function(see 为 Emacs Lisp 函数添加建议)将新函数与原有钩子函数组合。
需要注意的是,部分单函数钩子可能为nil,而add-function 无法处理这种情况,因此在调用前必须先进行检查。
本节介绍用于运行标准钩子的 run-hooks 函数,同时也说明运行各类非标准钩子的相关函数。
该函数接收一个或多个标准钩子变量名作为参数,并依次运行每个钩子。每个参数都应为表示标准钩子变量的符号。参数将按指定顺序处理。
若钩子变量的值非 nil,则该值应为一个函数列表。run-hooks 会依次无参数调用列表中的所有函数。
钩子变量的值也可以是单个函数—可以是 lambda 表达式或带有函数定义的符号—run-hooks 同样会调用该函数。但这种用法已被废弃。
若钩子变量为缓冲区局部变量,则会使用该局部变量而非全局变量。但如果局部变量中包含元素 t,则全局钩子变量也会一并运行。
该函数运行一个非标准钩子,依次调用 hook 中的所有钩子函数,并将参数 args 传递给每个函数。
该函数运行一个非标准钩子,依次调用各个钩子函数,若某个函数返回 nil 表示执行失败则停止运行。
所有函数均接收参数 args。若因函数执行失败而停止,该函数返回 nil;否则返回非 nil 值。
该函数运行一个非标准钩子,依次调用各个钩子函数,若某个函数返回非 nil 值表示执行成功则停止运行。
所有函数均接收参数 args。若因函数执行成功而停止,则返回该函数的返回值;否则返回 nil。
下面是一个示例,将函数添加到模式钩子中,使其在 Lisp 交互模式下自动启用自动填充模式:
(add-hook 'lisp-interaction-mode-hook 'auto-fill-mode)
钩子变量的值应为一个函数列表。你可以使用常规的 Lisp 操作来处理该列表,
但更模块化的方式是使用下文定义的 add-hook 和 remove-hook 函数。
它们会妥善处理一些特殊场景以避免问题。
将 lambda 表达式形式的函数添加到钩子中是可行的,但我们建议避免这样做,因为容易造成混淆。
若你再次添加写法略有不同的相同逻辑 lambda 表达式,钩子中会出现两个功能等价但互不相同的函数。
当你删除其中一个后,另一个仍会保留在钩子中。
该函数用于便捷地将函数 function 添加到钩子变量 hook 中。 它同时适用于标准钩子与非标准钩子。function 可以是任意能接收该钩子所需参数数量的 Lisp 函数。例如:
(add-hook 'text-mode-hook 'my-text-hook-function)
将 my-text-hook-function 添加到名为 text-mode-hook 的钩子中。
若 function 已存在于 hook 中(通过 equal 比较),则 add-hook 不会重复添加。
若 function 具有非 nil 的 permanent-local-hook 属性,则 kill-all-local-variables(或切换主模式)不会将其从钩子变量的局部值中移除。
对于标准钩子,钩子函数的设计应保证执行顺序无关紧要。任何对执行顺序的依赖都可能引发问题。
不过执行顺序是可预期的:通常 function 会被添加到钩子列表头部,因此会优先执行(除非再次调用 add-hook)。
某些场景下需要精确控制钩子中函数的相对顺序。
可选参数 depth 用于指定函数插入位置:取值为 -100 到 100 之间的数字,
数值越大,函数越靠近列表尾部。depth 默认值为 0;
为兼容旧版,当 depth 为非 nil 符号时,按深度 90 处理。
此外,当 depth 严格大于 0 时,该函数会被添加到同深度函数的 后面。
永远不要使用深度 100 或 -100,因为无法确保不会有其他函数需要更靠前或更靠后的位置。
add-hook 可以处理 hook 未定义或其值为单个函数的情况,会自动将其设置或修改为函数列表。
若 local 非 nil,则将 function 添加到缓冲区局部钩子列表而非全局钩子列表。
这会使该钩子成为缓冲区局部变量,并在局部值中添加 t,该标记表示同时运行默认值与局部值中的钩子函数。
该函数从钩子变量 hook 中移除 function。
它通过 equal 比较 function 与钩子列表中的元素,因此对符号与 lambda 表达式均有效。
若 local 非 nil,则从缓冲区局部钩子列表而非全局钩子列表中移除 function。
主模式用于定制 Emacs,使其适配特定类型文本的编辑与交互。每个缓冲区在同一时刻只能拥有一个主模式。 每个主模式都对应一个 主模式命令(major mode command),其名称应以 ‘-mode’ 结尾。 该命令负责在当前缓冲区切换至对应模式,通过设置局部键盘映射等各类缓冲区局部变量实现。See 主模式编码规范。 注意,与次模式不同,主模式无法直接 “关闭(turn off)”,只能将缓冲区切换至其他主模式。 不过你可以临时 挂起 主模式,并在之后 恢复 该挂起模式,详见下文。
通用性最强的主模式称为 基本模式(Fundamental mode),该模式不包含任何特定于模式的定义与变量设置。
该函数功能与fundamental-mode 类似,会清空所有缓冲区局部变量,同时会记录当前生效的主模式,以便后续恢复。
当你需要将缓冲区临时设置为 Emacs 不会自动选择的专用模式(see Emacs 如何选择主模式),
且希望之后能切回原始模式时,该函数与major-mode-restore(见下文)十分实用。
该函数用于恢复由 major-mode-suspend 记录的主模式。
若未记录任何主模式,则调用 normal-mode(see normal-mode);
若参数 avoided-modes 非空,则会强制排除该列表中的模式。
切换主模式会清空大部分局部变量,但不会移除缓冲区中的文本属性、覆盖层等所有痕迹。
通常很少需要在不同主模式之间直接切换(从基本模式切换至其他模式除外),因此一般无需关注该问题。
在调试缓冲区问题等场景下,有时需要对缓冲区进行 “完全重置(full reset)”,这正是clean-mode 主模式的用途。
它会清空所有局部变量(包括永久局部变量),同时移除所有覆盖层与文本属性。
编写主模式最简单的方式是使用宏define-derived-mode,该宏可基于已有主模式创建新的派生主模式。
See 定义派生模式。
即使新主模式并非明显派生自其他模式,我们仍推荐使用define-derived-mode,
它会自动遵循多项编码规范。常用的基础派生主模式,See 基础主模式。
标准 GNU Emacs Lisp 目录树中包含多个主模式的实现代码, 例如 text-mode.el、texinfo.el、lisp-mode.el 与 rmail.el 等文件。你可以通过这些库学习主模式的编写方法。
该变量的缓冲区局部值保存着当前主模式对应的符号,其默认值为新缓冲区的默认主模式,标准默认值为fundamental-mode。
若默认值为nil,则当 Emacs 通过C-x b(switch-to-buffer)等命令创建新缓冲区时,
新缓冲区会沿用此前当前缓冲区的主模式。
存在一个例外:若前一个缓冲区的主模式拥有值为special 的mode-class 符号属性,则新缓冲区会使用基本模式(see 主模式编码规范)。
每个主模式的代码都应当遵循一系列编码规范,包括局部键盘映射、语法表初始化、函数与变量命名以及钩子相关规范。
如果你使用 define-derived-mode 宏,它会自动处理其中大部分规范。See 定义派生模式。同时注意,基本模式是很多规范的例外,因为它代表 Emacs 的默认状态。
下面列出的规范仅为部分内容。每个主模式都应尽量与其他 Emacs 主模式保持整体一致,从而让 Emacs 整体更加协调。这里无法列出所有可能涉及一致性的细节;如果 Emacs 开发者指出你的主模式在某方面不符合通用规范,请进行兼容修改。
文档字符串中可以包含特殊文档子串 ‘\[command]’, ‘\{keymap}’ 和 ‘\<keymap>’,使帮助显示能自动适应用户自定义的按键绑定。See 文档中的按键绑定替换。
kill-all-local-variables。该函数会运行标准钩子 change-major-mode-hook,然后清除此前生效主模式的缓冲区局部变量。See 创建与删除缓冲区局部绑定。
major-mode 设置为该主模式命令对应的符号。describe-mode 依靠该值确定需要显示的文档。
mode-name 设置为模式的 “友好(pretty)” 名称,通常为字符串(其他形式参见 模式行的数据结构)。模式名称会显示在模式行中。
indent-line-function 设置为合适的函数,并可能需要定制其他缩进相关变量。See 代码自动缩进。
use-local-map 安装该局部映射。更多信息,See 活跃按键映射表。
该键盘映射应永久保存在名为 modename-mode-map 的全局变量中。通常由定义该模式的库完成变量设置。
关于编写模式键盘映射变量的代码建议,See 稳健定义变量的技巧。
主模式也可以重新绑定 M-n、M-p 和 M-s。M-n 与 M-p 的绑定通常应实现某种向前/向后移动功能,但不一定是光标移动。
如果主模式中某个命令能更适配当前文本并完成相同功能,重新绑定标准按键序列是合理的。例如,某编程语言编辑主模式可以重新定义 C-M-a,使其按该语言语法更好地跳转到函数开头。为适配主模式需求定制 C-M-a,推荐方式是设置 beginning-of-defun-function(see Moving over Balanced Expressions)调用模式专用函数。
如果某个标准按键的默认含义在该模式下基本无用,主模式重新绑定它也是合理的。例如小缓冲区模式会重新绑定 M-r,其默认功能在小缓冲区中几乎无用。Dired、Rmail 这类不允许文本自插入的主模式,可以合理地将字母与其他可打印字符重新定义为专用命令。
modename-mode-syntax-table 的变量中。See Syntax Tables。
modename-mode-abbrev-table 的变量中。如果主模式命令自身定义了缩写,应在调用 define-abbrev 时为 system-flag 参数传入 t。See Defining Abbrevs。
font-lock-defaults 设置缓冲区局部值。See Font Lock Mode。
context-menu-mode 时使用(see Menu Mouse Clicks in The Emacs Manual)。为此需要定义一个模式专用函数,根据缓冲区中 mouse-3 点击位置构建一个或多个菜单,并将该函数添加到 context-menu-functions 的缓冲区局部值中。
imenu-generic-expression、或 imenu-prev-index-position-function 与 imenu-extract-index-name-function 这两个变量、或 imenu-create-index-function 设置缓冲区局部值。See Imenu。
outline-regexp 或 outline-search-function 以及 outline-level 设置缓冲区局部值。See 大纲次要模式。
eldoc-documentation-functions 添加一个或多个缓冲区局部条目。
completion-at-point-functions 添加缓冲区局部条目,指定各类关键字的补全方式。See 普通缓冲区中的补全。
make-local-variable,而非 make-variable-buffer-local。后者会使该变量在之后所有设置过它的缓冲区中均为局部,会影响不使用该模式的缓冲区。模式不应当产生此类全局影响。See 缓冲区局部变量。
除极少数例外,Lisp 包中使用 make-variable-buffer-local 的合理场景,仅限仅在该包内部使用的变量。若用于其他包也会使用的变量,会造成相互干扰。
modename-mode-hook 的标准模式钩子(mode hook)。主模式命令的**最后一步**必须调用 run-mode-hooks。该函数会依次运行标准钩子 change-major-mode-after-body-hook、模式钩子、函数 hack-local-variables(缓冲区访问文件时),然后运行标准钩子 after-change-major-mode-hook。See 模式钩子。
define-derived-mode 宏定义,但并非强制要求。此类模式应在 delay-mode-hooks 表达式内部调用父模式命令(使用 define-derived-mode 会自动完成这一点)。See 定义派生模式 和 模式钩子。
change-major-mode-hook 设置缓冲区局部值。See 创建与删除缓冲区局部绑定。
mode-class、值为 special 的属性,示例如下:
(put 'funny-mode 'mode-class 'special)
这会告知 Emacs:即使 major-mode 默认值为 nil,在当前缓冲区为 Funny 模式时新建的缓冲区也不会继承该模式。默认情况下 major-mode 为 nil 时新建缓冲区会沿用当前缓冲区主模式(see Emacs 如何选择主模式),但此类special 模式会改用基本模式。Dired、Rmail、缓冲区列表等模式均使用该特性。
view-buffer 函数不会在 mode-class 为 special 的缓冲区中启用查看模式,因为这类模式通常自带类似查看模式的绑定。
如果父模式为 special 模式,define-derived-mode 宏会自动将派生模式标记为 special。特殊模式(Special mode)是此类模式方便继承的父模式;See 基础主模式。
auto-mode-alist 添加条目,为对应文件名指定该模式(see Emacs 如何选择主模式)。如果将模式命令定义为自动加载,应在调用 autoload 的同一文件中添加该条目。如果为模式命令使用了自动加载标记,也可以为添加该条目的代码使用自动加载标记(see autoload cookie)。如果不使用自动加载,在包含模式定义的文件中添加条目即可。
defvar 或 defcustom 设置模式相关变量,避免变量已有值时被重复初始化。See 定义全局变量。
Emacs 在打开文件时,会根据文件名或文件内部信息,自动为缓冲区选择合适的主模式。它同时会处理文件文本中指定的局部变量。
该函数为当前缓冲区设置合适的主模式与缓冲区局部变量绑定。它会调用 set-auto-mode(见下文)。从 Emacs 26.1 开始,该函数不再运行 hack-local-variables,该操作改在主模式初始化阶段的 run-mode-hooks 中执行(see 模式钩子)。
如果 normal-mode 的参数 find-file 非空,则表明该函数由 find-file 调用。此时它会处理文件首行 ‘-*-’ 格式或文件尾部的局部变量。变量 enable-local-variables 控制是否执行该操作。文件局部变量段的语法参见 See Local Variables in Files in The GNU Emacs Manual。
如果以交互方式运行 normal-mode,参数 find-file 通常为 nil。此时 normal-mode 会无条件处理所有文件局部变量。
该函数会调用 set-auto-mode 选择并设置主模式。若未匹配到任何模式,缓冲区将保持 major-mode 默认值所指定的主模式(见下文)。
normal-mode 在调用主模式命令时使用 condition-case 捕获异常,并以 ‘文件模式指定错误(File mode specification error)’ 的形式报告原始错误信息。
该函数为当前缓冲区选择并设置合适的主模式,决策依据按优先级依次为:文件首行 ‘-*-’ 标记、文件尾部的 ‘mode:’ 局部变量、‘#!’ 解释器行(通过 interpreter-mode-alist)、缓冲区开头文本(通过 magic-mode-alist),最后是所访问的文件名(通过 auto-mode-alist)。See How Major Modes are Chosen in The GNU Emacs Manual。若 enable-local-variables 为 nil,则 set-auto-mode 不会检查 ‘-*-’ 行与文件尾部的模式标记。
某些文件类型不适合通过扫描内容识别模式。例如 tar 归档文件尾部可能包含带有局部变量段的成员文件,不应将其模式应用于整个归档文件;又如 TIFF 图像文件首行可能恰好形似 ‘-*-’ 格式。为此,这类文件扩展名均已加入 inhibit-local-variables-regexps 列表。向该列表添加正则表达式可阻止 Emacs 从中搜索任何类型的局部变量(不仅限于模式标记)。
若 keep-mode-if-same 非空,且缓冲区已处于正确主模式,则该函数不会重复调用模式命令。例如 set-visited-file-name 会将其设为 t,避免清除用户已设置的缓冲区局部变量。
该函数将 buffer 的主模式设为 major-mode 的默认值;若默认值为 nil,则使用当前缓冲区的主模式(如适用)。一个例外是:若缓冲区名为 *scratch*,则将模式设为 initial-major-mode。
创建缓冲区的底层原语不使用该函数,但 switch-to-buffer、find-file-noselect 等中层命令在创建缓冲区时均会调用。
该变量的值决定初始 *scratch* 缓冲区的主模式,取值应为主模式命令对应的符号,默认值为 lisp-interaction-mode。
该变量用于为 ‘#!’ 行指定解释器的脚本文件匹配主模式。其值为关联列表,元素格式为 (regexp . mode),表示若文件解释器匹配 \\`regexp\\', 则使用 mode 模式。例如默认元素 ("python[0-9.]*" . python-mode)。
该变量为关联列表,元素格式为 (regexp . function),其中 regexp 为正则表达式,function 为函数或 nil。打开文件后,若缓冲区开头文本匹配 regexp 且 function 非空,则 set-auto-mode 会调用该函数;若 function 为 nil,则交由 auto-mode-alist 决定模式。
用法与 magic-mode-alist 相同,但仅在 auto-mode-alist 未匹配到模式时生效。
该变量为关联列表,由文件名正则表达式与对应主模式命令组成。通常匹配文件名后缀,如 ‘.el’、‘.c’,但也可匹配其他规则。普通元素格式为 (regexp . mode-function)。
示例:
(("\\`/tmp/fol/" . text-mode)
("\\.texinfo\\'" . texinfo-mode)
("\\.texi\\'" . texinfo-mode)
("\\.el\\'" . emacs-lisp-mode)
("\\.c\\'" . c-mode)
("\\.h\\'" . c-mode)
...)
当你打开一个文件时,如果其扩展文件名(see 文件名展开相关函数)在通过 file-name-sans-versions(see 文件名组成部分)去除版本号与备份后缀后,匹配了某个 regexp 正则表达式,set-auto-mode 就会调用对应的 mode-function。该功能让 Emacs 能够为绝大多数文件选择合适的主模式。
如果 auto-mode-alist 中的某个元素格式为 (regexp function t),那么在调用 function 之后,Emacs 会使用文件名中之前未匹配的部分,再次搜索 auto-mode-alist。这一特性对解压缩相关包非常实用:形如 ("\\.gz\\'" function t) 的条目可以先对文件解压,再根据去掉 ‘.gz’ 后的文件名,为解压后的文件设置正确模式。
如果 auto-mode-alist 中有多个元素的 regexp 都能匹配该文件名,Emacs 会使用第一个匹配项。
下面示例展示如何将多组模式规则添加到 auto-mode-alist 头部。(你可以在初始化文件中使用这类表达式。)
(setq auto-mode-alist (append ;; File name (within directory) starts with a dot. '(("/\\.[^/]*\\'" . fundamental-mode) ;; File name has no dot. ("/[^\\./]*\\'" . fundamental-mode) ;; File name ends in ‘.C’. ("\\.C\\'" . c++-mode)) auto-mode-alist))
该变量是一个关联列表,用于指定激活某个主模式时实际应调用的函数。适用于可被多种主模式支持的文件格式,通过该变量可以指定默认使用的替代模式。
例如,某个第三方包提供了大幅改进的 Pascal 主模式,可以通过下面代码告知 normal-mode,对原本应使用 pascal-mode 的所有文件,改用 spiffy-pascal-mode:
(add-to-list 'major-mode-remap-defaults '(pascal-mode . spiffy-pascal-mode))
该变量格式与 major-mode-remap-alist 相同。如果两个列表同时匹配某个主模式,优先使用 major-mode-remap-alist 中的条目。
该函数根据 major-mode-remap-alist 和 major-mode-remap-defaults,返回替代 mode 使用的主模式。如果这些变量未对该模式进行重映射,则返回 mode 本身。
当某个程序包需要为特定文件格式激活主模式时,应当使用此函数,并将该文件格式的标准主模式作为 mode 参数传入,以确定实际要激活的具体模式,从而兼顾用户的偏好设置。
describe-mode 函数用于提供主模式的相关信息。该命令默认绑定到按键 C-h m。它使用变量 major-mode 的值(see 主模式),这也是每个主模式命令都需要设置该变量的原因。
该命令显示当前缓冲区的主模式与次要模式的文档。它通过 documentation 函数获取主模式与次要模式命令的文档字符串(see 访问文档字符串)。
如果从 Lisp 中调用时传入非 nil 的 buffer 参数,此函数将显示该缓冲区的主模式与次要模式文档,而非当前缓冲区的文档。
定义新主模式的推荐方式是使用 define-derived-mode 从已有模式进行派生。若没有密切相关的模式,应继承自 text-mode、special-mode 或 prog-mode 之一。See 基础主模式。若这些均不适用,则可继承自 fundamental-mode(see 主模式)。
该宏将 variant 定义为主模式命令,使用 name 作为该模式名称的字符串形式。variant 与 parent 应为不带引号的符号。
新定义的命令 variant 会先调用函数 parent,随后覆盖父模式的部分特性:
variant-map。define-derived-mode 会将父模式的按键映射设为新映射表的父映射,除非 variant-map 已被设置且已存在父映射。
variant-syntax-table 中,除非使用 :syntax-table 关键字另行指定(见下文)。define-derived-mode 会将父模式的语法表设为 variant-syntax-table 的父语法表,除非后者已被设置且其父表并非标准语法表。
variant-abbrev-table 中,除非使用 :abbrev-table 关键字另行指定(见下文)。
variant-hook。它会在执行完所有祖先模式的钩子后,通过 run-mode-hooks 运行该钩子,作为最后一步操作,之后再执行可能存在的 :after-hook 代码。See 模式钩子。
此外,可通过 body 指定覆盖父模式 parent 的其他特性。命令 variant 会在完成所有常规覆盖设置后、运行模式钩子之前,执行 body 中的表达式。
若父模式 parent 拥有非 nil 的 mode-class 符号属性,define-derived-mode 会将 variant 的 mode-class 属性设为相同值。例如,这可保证若父模式为特殊模式,则派生模式同样为特殊模式(see 主模式编码规范)。
也可为 parent 指定 nil,使新模式无父模式。此时 define-derived-mode 仍按上述规则执行,但会省略所有与父模式相关的操作。
反之,可使用下文介绍的 derived-mode-set-parent 与 derived-mode-add-parents 显式设置新模式的继承关系。
参数 docstring 为新模式指定文档字符串。define-derived-mode 会在该文档末尾自动添加关于模式钩子与按键映射的通用信息。若省略 docstring,则由 define-derived-mode 自动生成文档。
keyword-args 为关键字与值组成的键值对。除 :after-hook 外,其余关键字对应的值均会被求值。当前支持的关键字如下:
:syntax-table用于为新模式显式指定语法表。若指定值为 nil,新模式将使用与父模式 parent 相同的语法表;若父模式为 nil,则使用标准语法表。(注意:此处不遵循非关键字参数的惯例,nil 值不等同于不指定该参数。)
:abbrev-table用于为新模式显式指定缩写表。若指定值为 nil,新模式将使用与父模式 parent 相同的缩写表;若父模式为 nil,则使用 fundamental-mode-abbrev-table。(同样,nil 值 不等同于不指定该关键字。)
:interactive模式默认均为交互式命令。若指定值为 nil,此处定义的模式将不具备交互性。该设置适用于无需用户手动激活、仅用于特定格式缓冲区的模式。
:group若指定该关键字,其值应为该模式对应的自定义组。(并非所有主模式都拥有自定义组。)命令 customize-mode 会使用该设置。define-derived-mode 并不会自动创建指定的自定义组。
:after-hook该可选关键字指定一个单独的 Lisp 表达式,作为模式函数的最后一步操作,在模式钩子运行完成后执行。该表达式无需加引号。由于该表达式可能在模式函数结束后才被求值,因此不应访问模式函数的任何局部状态。:after-hook 常用于设置依赖于用户配置的模式特性,而这些配置可能在模式钩子中被修改。
以下为一个示例:
(defvar-keymap hypertext-mode-map "<down-mouse-3>" #'do-hyper-link) (define-derived-mode hypertext-mode text-mode "Hypertext" "Major mode for hypertext." (setq-local case-fold-search nil))
无需在定义中书写 interactive 声明;define-derived-mode 会自动完成该设置。
若当前主模式继承自符号列表 modes 中的任意一个主模式,该函数返回非 nil。
modes 也可直接传入单个模式符号,而非列表。
此外,本函数仍支持已废弃的调用方式:将 modes 以多个独立参数形式传入。
在检查当前主模式的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。
若模式 mode 继承自符号列表 modes 中的任意一个主模式,该函数返回非 nil。
与 derived-mode-p 相同,modes 可传入单个符号,且同样支持已废弃的多参数调用方式。
在检查 mode 的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。
主模式的继承关系图谱可通过以下底层函数访问与修改:
该函数声明模式 mode 继承自 parent。
define-derived-mode 在定义完 mode 后会调用此函数,以登记 mode 基于 parent 派生的关系。
该函数允许在定义 mode 时使用的父模式之外,注册额外的父模式。当 mode 与 extra-parents 中的模式存在相似性,且需要在目录局部变量、模式专属配置等场景中将 mode 视为这些模式的子模式时,可使用该函数。额外父模式以符号列表形式在 extra-parents 中指定。
derived-mode-p 与 provided-mode-derived-p 会将这些额外父模式视为 mode 的父模式之一。
该函数返回 mode 所有继承关系中的模式列表,按从最具体到最通用排序,并以 mode 自身开头。列表包含通过 derived-mode-add-parents 添加的额外父模式(若有)。
除基本模式外,还有三种主模式是其他主模式常用的派生来源:文本模式、编程模式和特殊模式。文本模式本身就很实用(例如用于编辑后缀为 .txt 的文件),而编程模式与特殊模式主要用于供其他模式从中派生。
新建的主模式应尽可能直接或间接从这三种模式之一派生。原因之一是,这样用户可以通过一个统一的模式钩子(例如 prog-mode-hook)为一整类相关模式(例如所有编程语言模式)进行自定义配置。
文本模式是用于编辑人类语言文本的主模式。它将字符 ‘"’ 和 ‘\’ 定义为标点符号语法(see Table of Syntax Classes),并设置 completion-at-point 根据拼写词典进行单词补全(see 普通缓冲区中的补全)。
从文本模式派生的主模式示例是 HTML 模式。See SGML and HTML Modes in The GNU Emacs Manual。
编程模式是用于编辑编程语言源代码缓冲区的基础主模式。Emacs 内置的大多数编程语言主模式均从该模式派生。
编程模式将 parse-sexp-ignore-comments 设为 t(see Motion Commands Based on Parsing),并将 bidi-paragraph-direction 设为 left-to-right(see Bidirectional Display)。
特殊模式是一类基础主模式,用于显示由 Emacs 专门生成、而非直接来自文件的文本缓冲区。从特殊模式派生的主模式会被赋予 special 类型的 mode-class 属性(see 主模式编码规范)。
特殊模式会将缓冲区设为只读。其按键映射中定义了若干常用绑定,包括 q 对应 quit-window,g 对应 revert-buffer(see 恢复缓冲区)。
从特殊模式派生的主模式示例是缓冲区菜单模式,该模式用于 *Buffer List* 缓冲区。See Listing Existing Buffers in The GNU Emacs Manual。
此外,用于展示表格化数据的缓冲区模式可以从列表表格模式继承,而该模式本身又派生自特殊模式。See 表格列表模式。
每个主模式命令在执行完毕时,都应运行与模式无关的通用钩子 change-major-mode-after-body-hook、自身的模式钩子,以及通用钩子 after-change-major-mode-hook。
这一过程通过调用 run-mode-hooks 实现。如果该主模式是派生模式,即在其内部调用了另一个主模式(父模式),则应将相关代码放在 delay-mode-hooks 内部,以避免父模式自行运行这些钩子。
取而代之,由派生模式调用的 run-mode-hooks 会一并运行父模式的钩子。See 主模式编码规范。
Emacs 22 之前的版本不包含 delay-mode-hooks。24 之前的版本不包含 change-major-mode-after-body-hook。
如果用户实现的主模式未使用 run-mode-hooks,也未更新以支持这些新特性,就无法完全遵循上述规范:它们可能过早运行父模式的钩子,或未能运行 after-change-major-mode-hook。
这会产生不良后果,例如导致使用 define-globalized-minor-mode 定义的全局次要模式无法在使用这类主模式的缓冲区中启用。
如果你遇到此类主模式,建议修正其实现以遵循规范。
当你使用 define-derived-mode 定义主模式时,会自动确保遵循上述规范。
如果不使用 define-derived-mode 而“手动”定义主模式,则可使用下面的函数来自动处理这些规范。
主模式应使用该函数运行其模式钩子。它与 run-hooks 类似(see 钩子),但还会运行 change-major-mode-after-body-hook、hack-local-variables(当缓冲区关联文件时)(see 文件局部变量)以及 after-change-major-mode-hook。
该函数最后会执行父模式中声明的 :after-hook 代码(see 定义派生模式)。
若在 delay-mode-hooks 代码块执行期间调用该函数,它不会立即运行钩子、执行 hack-local-variables 或求值相关代码,而是将这些操作推迟到 delay-mode-hooks 结束后的下一次 run-mode-hooks 调用时统一执行。
当一个主模式命令调用另一个主模式时,应将调用逻辑放在 delay-mode-hooks 内部。
该宏会执行 body,但会告知执行期间所有 run-mode-hooks 调用暂缓运行钩子。
这些钩子会在 delay-mode-hooks 结构结束后的下一次 run-mode-hooks 调用时实际运行。
这是由 run-mode-hooks 运行的通用钩子,执行时机在模式钩子之前。
这是由 run-mode-hooks 运行的通用钩子,在每个规范实现的主模式命令最后执行。
表格列表模式是一种用于展示表格化数据的主模式,即由 条目(entries) 构成的数据,每个条目占据一行文本,内容按列划分。表格列表模式提供了行列美观排版、按各列数值对行排序的功能。它派生自特殊模式(see 基础主模式)。
表格列表模式面向使用等宽字体、单一字体与字号展示文本的场景。若需要使用变宽字体或图片展示表格,可改用 make-vtable。虚拟表格(vtable)还支持在一个缓冲区中放置多个表格,或缓冲区同时包含表格与额外文本。更多信息,See (vtable)Introduction。
表格列表模式适合作为更专用主模式的父模式。例如进程菜单模式(see Process Information)与包菜单模式(see Package Menu in The GNU Emacs Manual)。
这类派生模式应照常使用 define-derived-mode,并将 tabulated-list-mode 指定为第二个参数(see 定义派生模式)。define-derived-mode 表达式的主体部分需为下方文档所述变量赋值,以指定表格数据格式;可选地,随后可调用 tabulated-list-init-header 函数,用列名生成表头。
派生模式还应定义一个列表命令(listing command)。用户实际调用的是该命令(如 M-x list-processes),而非模式命令本身。列表命令需要创建或切换至缓冲区、启用派生模式、指定表格数据,最终调用 tabulated-list-print 填充缓冲区内容。
该变量指定在图形框架中用于标记列按升序排序的字符。
在表格列表缓冲区中切换排序方向时,该标记会在升序(“asc”)与降序(“desc”)之间切换。
与 tabulated-list-gui-sort-indicator-asc 类似,用于标记列按降序排序。
与 tabulated-list-gui-sort-indicator-asc 类似,用于文本模式框架。
与 tabulated-list-tty-sort-indicator-asc 类似,用于标记列按降序排序。
该缓冲区局部变量指定表格列表数据的格式,取值为一个向量。向量中每个元素代表一列数据,格式为列表 (name width sort . props),其中:
该缓冲区局部变量指定表格列表缓冲区中展示的条目,取值为列表或函数。
若为列表,每个元素对应一个条目,格式为 (id contents),其中:
nil 或用于标识条目的 Lisp 对象。若为后者,重新排序时点会保持在同一条目上,比较使用 equal。
tabulated-list-format 长度相同的向量。
每个向量元素可以是直接插入缓冲区的字符串、用于插入图片的图片描述符(see Image Descriptors),
或列表 (label . properties)—后者会通过 insert-text-button 以 label 和 properties 为参数插入文本按钮(see Making Buttons)。
所有字符串中不应包含换行符。
若为函数,则该函数无参调用时需返回上述格式的列表。
该缓冲区局部变量指定表格列表缓冲区中展示的条目分组,取值为列表或函数。
若为列表,每个元素对应一个分组,格式为 (group-name entries),其中 group-name 为分组前显示的字符串,entries 格式与 tabulated-list-entries 相同(见上文)。
若为函数,则该函数无参调用时需返回上述格式的列表。
可使用 seq-group-by 从 tabulated-list-entries 生成 tabulated-list-groups,示例:
(setq tabulated-list-groups
(seq-group-by 'Buffer-menu-group-by-mode
tabulated-list-entries))
其中 Buffer-menu-group-by-mode 可如下定义:
(defun Buffer-menu-group-by-mode (entry) (concat "* " (aref (cadr entry) 5)))
该通用钩子在表格列表缓冲区恢复前运行。派生模式可向该钩子添加函数以重新计算 tabulated-list-entries。
该变量的值为在当前位置插入条目(含结尾换行符)的函数。函数接收两个参数 id 与 contents,含义与 tabulated-list-entries 中一致。默认值为以常规方式插入条目的函数;更复杂使用表格列表模式的模式可指定其他函数。
该变量指定表格列表缓冲区当前的排序键。为 nil 时不排序。否则格式为 (name . flip),其中 name 为与 tabulated-list-format 中列名匹配的字符串,flip 非 nil 时表示反转排序顺序。
该函数计算并设置表格列表缓冲区的 header-line-format(see 窗口标题栏),并为表头行绑定按键映射,支持点击列标题排序条目。
从表格列表模式派生的模式应在设置上述变量后调用该函数(尤其需先设置 tabulated-list-format)。
该函数用条目填充当前缓冲区,应由列表命令调用。它清空缓冲区,按 tabulated-list-sort-key 对 tabulated-list-entries 指定的条目排序,随后调用 tabulated-list-printer 指定的函数插入每条目。
若可选参数 remember-pos 非 nil,函数会查找当前行的 id(若有),并在所有条目重新插入后尝试定位到该条目。
若可选参数 update 非 nil,函数仅删除或添加自上次打印后发生变化的条目。在大多数条目未改变时,速度可快数倍。唯一结果差异是:通过 tabulated-list-put-tag 添加的标记不会从未变化的条目上移除(常规情况下所有标记都会被清除)。
该函数删除当前位置的条目。
返回列表 (id cols),其中 id 为被删除条目标识,cols 为其列描述向量。点会移至当前行开头。当前位置无条目时返回 nil。
注意:该函数仅修改缓冲区内容,不改变 tabulated-list-entries。
该 defsubst 从 tabulated-list-entries(列表时)或其函数返回的列表中获取标识对象。pos 省略或为 nil 时默认为点。
该 defsubst 从 tabulated-list-entries(列表时)或其函数返回的列表中获取位置 pos 处标识对应的条目向量。该位置无条目时返回 nil。
该 defsubst 在 pos 处存在伪表头时返回非 nil。当 tabulated-list-use-header-line 为 nil 时,会使用伪表头在缓冲区开头显示列名。pos 省略或为 nil 时默认为 point-min。
该函数在当前行的填充区域放置标记 tag。填充区域为行首空白,宽度由 tabulated-list-padding 控制。tag 为字符串,长度不超过 tabulated-list-padding。若 advance 非 nil,点向下移动一行。
该函数清除当前缓冲区中所有填充区域的标记。
该函数修改当前位置的表格列表条目,将第 col 列设为 desc。col 为列号或列名,desc 为新列描述,通过 tabulated-list-print-col 插入。
若 change-entry-data 非 nil,函数会修改底层数据(通常为 tabulated-list-entries 列表中的列描述),将对应向量位置设为 desc。
通用模式(Generic modes) 是具备注释语法与字体锁定模式基础支持的简易主模式。定义通用模式可使用宏 define-generic-mode。文件 generic-x.el 中包含若干使用 define-generic-mode 的示例。
该宏定义一个名为 mode 的通用模式命令(符号,无需引号)。可选参数 docstring 为该模式命令的文档字符串;若未提供,define-generic-mode 会自动生成默认文档。
参数 comment-list 为一个列表,每个元素可以是字符、单个或双字符的字符串,或序对。字符或字符串会在该模式的语法表中设为注释起始符。若元素为序对,则 CAR 设为注释起始符,CDR 设为注释结束符(若希望注释在行尾结束,可将后者设为 nil)。注意,语法表机制对可使用的注释起止符存在限制,参见 See Syntax Tables。
参数 keyword-list 为需要以 font-lock-keyword-face 高亮的关键字列表,每个关键字为字符串。而 font-lock-list 为需要高亮的额外表达式列表,其中每个元素的格式与 font-lock-keywords 中的元素一致,参见 See 基于搜索的字体高亮。
参数 auto-mode-list 为一组正则表达式,会被添加到变量 auto-mode-alist 中;添加动作在 define-generic-mode 表达式执行时完成,而非宏展开阶段。
最后,function-list 为模式命令用于执行额外初始化的函数列表。这些函数会在运行模式钩子变量 mode-hook 之前被调用。
文本模式或许是除基本模式外最简单的模式。以下摘自 text-mode.el 的代码片段展示了上述诸多规范的用法:
;; 为此模式创建语法表。
(defvar text-mode-syntax-table
(let ((st (make-syntax-table)))
(modify-syntax-entry ?\" ". " st)
(modify-syntax-entry ?\\ ". " st)
;; Add 'p' so M-c on 'hello' leads to 'Hello', not 'hello'.
(modify-syntax-entry ?' "w p" st)
...
st)
"Syntax table used while in `text-mode'.")
以下是实际模式命令的定义方式:
(define-derived-mode text-mode nil "Text"
"用于编辑人类可读文本的主模式。
该模式中,段落仅以空行或空白行分隔。
因此可充分使用自适应填充功能
(参见变量 `adaptive-fill-mode')。
\\{text-mode-map}
启用文本模式时会运行通用钩子 `text-mode-hook'。"
(setq-local require-final-newline mode-require-final-newline))
三种 Lisp 模式(Lisp 模式、Emacs Lisp 模式、Lisp 交互模式)相比文本模式功能更多,代码也相应更复杂。以下摘自 lisp-mode.el 的片段展示了这类模式的实现方式。
以下为 Lisp 模式语法表与缩写表的定义:
;; 创建模式专用的表变量。
(define-abbrev-table 'lisp-mode-abbrev-table ()
"Abbrev table for Lisp mode.")
(defvar lisp-mode-syntax-table
(let ((table (make-syntax-table lisp--mode-syntax-table)))
(modify-syntax-entry ?\[ "_ " table)
(modify-syntax-entry ?\] "_ " table)
(modify-syntax-entry ?# "' 14" table)
(modify-syntax-entry ?| "\" 23bn" table)
table)
"Syntax table used in `lisp-mode'.")
三种 Lisp 相关模式共用大量代码。例如,Lisp 模式与 Emacs Lisp 模式继承自 Lisp 数据模式,而 Lisp 交互模式继承自 Emacs Lisp 模式。
Lisp 数据模式会设置 comment-start 变量以处理 Lisp 注释:
(setq-local comment-start ";") ...
不同 Lisp 模式的按键映射略有差异。例如,Lisp 模式将 C-c C-z 绑定到 run-lisp,而其他 Lisp 模式则没有该绑定。不过所有 Lisp 模式共用部分命令,以下代码设置了这些共用命令:
(defvar-keymap lisp-mode-shared-map :parent prog-mode-map :doc "各类 Lisp 模式共用命令的按键映射。" "C-M-q" #'indent-sexp "DEL" #'backward-delete-char-untabify)
以下为 Lisp 模式的按键映射设置代码:
(defvar-keymap lisp-mode-map :doc "普通 Lisp 模式的按键映射。 本映射继承 `lisp-mode-shared-map' 中的所有命令。" :parent lisp-mode-shared-map "C-M-x" #'lisp-eval-defun "C-c C-z" #'run-lisp)
最后是 Lisp 模式的主模式命令定义:
(define-derived-mode lisp-mode lisp-data-mode "Lisp"
"用于编辑非 GNU Emacs Lisp 的其他 Lisp 代码的主模式。
常用命令:
删除操作回退时会将制表符转换为空格。
空行分隔段落。分号开头为注释。
\\{lisp-mode-map}
`run-lisp' 既可用于启动下级 Lisp 进程,
也可切换回已存在的 Lisp 进程。"
(setq-local find-tag-default-function 'lisp-find-tag-default)
(setq-local comment-start-skip
"\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
(setq imenu-case-fold-search t))
次要模式(minor mode) 提供可选功能,用户可独立于主模式选择启用或关闭。次要模式可以单独启用,也可以组合启用。
大多数次要模式实现的功能与主模式无关,因此可在绝大多数主模式下使用。例如,自动填充模式可与任何允许插入文本的主模式配合工作。不过,也有少数次要模式专用于某个特定主模式。例如,差异自动优化模式是一个仅计划与差异模式配合使用的次要模式。
理想情况下,一个次要模式无论其他次要模式是否生效,都应正常发挥作用。启用和禁用次要模式的顺序应当可以任意。
这个缓冲区局部变量列出当前缓冲区中已启用的次要模式,值为一个符号列表。
该变量列出当前已启用的全局次要模式,值为一个符号列表。
该变量的值是所有次要模式命令的列表。
与主模式一样,编写次要模式也有相应规范(see 主模式)。这些规范将在下面说明。遵循它们最简单的方式是使用宏 define-minor-mode。See 定义次要模式。
nil,开启时为非 nil。如果该次要模式是缓冲区局部的,该变量也应当是缓冲区局部的。
该变量与 minor-mode-alist 配合使用,用于在模式行上显示次要模式名称。它还通过 minor-mode-map-alist 决定次要模式的按键映射是否生效(see 控制活跃按键映射表)。各个命令或钩子也可以检查它的值。
模式命令应接受一个可选参数。如果交互式调用且不带前缀参数,它应当切换模式状态(即关闭则开启,开启则关闭)。如果交互式调用并带有前缀参数,参数为正则开启模式,否则关闭。
如果模式命令从 Lisp 中调用(即非交互式),参数省略或为 nil 时应开启模式;参数为符号 toggle 时切换模式;其他情况则按照上述带数值前缀参数的交互式调用方式处理。
下面的示例展示了如何实现这种行为(与 define-minor-mode 宏生成的代码类似):
(interactive (list (or current-prefix-arg 'toggle)))
(let ((enable
(if (eq arg 'toggle)
(not foo-mode) ; this is the mode’s mode variable
(> (prefix-numeric-value arg) 0))))
(if enable
do-enable
do-disable))
这种略显复杂的行为设计,是为了方便用户交互式切换次要模式,同时也便于在模式钩子中直接启用次要模式,例如:
(add-hook 'text-mode-hook 'foo-mode)
无论 foo-mode 是否已经启用,这样写都能正确生效,因为从 Lisp 无参调用 foo-mode 命令时会无条件启用该次要模式。在模式钩子中禁用次要模式的写法会稍显繁琐:
(add-hook 'text-mode-hook (lambda () (foo-mode -1)))
不过这种用法并不常见。
连续两次启用或禁用同一个次要模式不应出错,且效果应与执行一次相同。换句话说,次要模式命令应当是幂等的。
minor-mode-alist 中添加一项(see Definition of minor-mode-alist)。该项应为如下形式的列表:
(mode-variable string)
其中 mode-variable 是控制次要模式启用的变量,string 是以空格开头的短字符串,用于在模式行上表示该模式。这些字符串必须简短,以便同时显示多个。
向 minor-mode-alist 添加项时,应使用 assq 检查是否已存在,避免重复。例如:
(unless (assq 'leif-mode minor-mode-alist) (push '(leif-mode " Leif") minor-mode-alist))
或者使用 add-to-list(see 修改列表变量):
(add-to-list 'minor-mode-alist '(leif-mode " Leif"))
此外,部分主模式规范(see 主模式编码规范)同样适用于次要模式:包括全局符号命名规范、初始化函数末尾使用钩子,以及按键映射和各类表的使用规范。
次要模式应尽可能支持通过自定义系统启用和关闭(see 自定义设置)。为此,模式变量应使用 defcustom 定义,通常指定 :type 'boolean。如果仅设置变量不足以启用模式,还应指定 :set 方法,通过调用模式命令来启用模式。在变量的文档字符串中说明:若非通过自定义系统设置该变量,可能不会生效。同时,使用自动加载标记标记该定义(see autoload cookie),并指定 :require,以便自定义该变量时会加载定义该模式的库。示例:
;;;###autoload (defcustom msb-mode nil "Toggle msb-mode. Setting this variable directly does not take effect; use either \\[customize] or the function `msb-mode'." :set 'custom-set-minor-mode :initialize 'custom-initialize-default :version "20.4" :type 'boolean :group 'msb :require 'msb)
每个次要模式都可以拥有自己的按键映射,在模式启用时生效。要为次要模式设置按键映射,需向关联列表 minor-mode-map-alist 中添加一项。See Definition of minor-mode-map-alist。
次要模式按键映射的一种用途是修改某些自插入字符的行为,使其在插入自身的同时执行其他操作。(另一种自定义 self-insert-command 的方式是通过 post-self-insert-hook,参见 User-Level Insertion Commands。除此之外,用于定制 self-insert-command 的工具仅适用于缩写和自动填充模式等特殊场景。请勿尝试用自定义定义替换标准的 self-insert-command。编辑器命令循环会特殊处理该函数。)
次要模式可以将命令绑定到以 C-c 开头、后跟标点符号的按键序列。但是,以 C-c 开头后跟 {}<>:; 之一、控制字符或数字的按键序列保留给主模式使用。同时,C-c 字母 保留给用户自定义。See Key Binding Conventions。
宏 define-minor-mode 提供了一种便捷方式,可在一个独立的定义中实现完整的次要模式。
该宏定义一个名称为 mode(符号)的新次要模式。它会定义一个名为 mode 的命令用于切换该次要模式,并以 doc 作为其文档字符串。
该切换命令接受一个可选(前缀)参数。交互式无参调用时会开启或关闭模式;正前缀参数开启模式,其他前缀参数关闭模式。在 Lisp 中调用时,参数为 toggle 表示切换状态,参数省略或为 nil 则开启模式。
这使得在主模式钩子中启用次要模式变得十分简便。若 doc 为 nil,宏会自动生成一段默认文档字符串说明上述行为。
默认情况下,它还会定义一个名为 mode 的变量,在模式启用或关闭时分别设为 t 或 nil。
keyword-args 由关键字及其对应值组成。部分关键字具有特殊含义:
:global global若非 nil,表示该次要模式为全局模式,而非缓冲区局部模式。默认为 nil。
将次要模式设为全局模式的效果之一,是使 mode 变量成为可自定义变量。通过自定义界面切换它即可开启或关闭模式,其值可保存以便后续 Emacs 会话使用(see Saving Customizations in The GNU Emacs Manual)。
为使保存的变量正常生效,应确保每次 Emacs 启动时该次要模式函数都可用,通常做法是将 define-minor-mode 表达式标记为自动加载。
:init-value init-value该值为变量 mode 的初始化值。除非特殊情况(见下文),否则该值必须为 nil。
:lighter lighter字符串 lighter 用于指定模式启用时在模式行上显示的内容;若为 nil,则不在模式行显示。
:keymap keymap可选参数 keymap 指定该次要模式的按键映射。若非 nil,它可以是一个变量名(其值为按键映射)、一个按键映射,或如下形式的关联列表:
(key-sequence . definition)
其中每个 按键序列 和 定义 都是可直接传给 define-key 的参数(see 修改按键绑定)。
若 keymap 是按键映射或关联列表,宏还会自动定义变量 mode-map。
:variable place用于替换存储模式状态的默认变量 mode。若指定此项,则不会定义 mode 变量,且 init-value 参数无效。
place 可以是另一个命名变量(需自行定义),或任何可与 setf 函数配合使用的对象(see 广义变量)。
place 也可以是一个序对 (get . set),其中 get 是返回当前状态的表达式,set 是接收一个状态参数并应赋值给 place 的单参数函数。
:after-hook after-hook定义一个单独的 Lisp 表达式,在模式钩子运行完毕后执行,无需加引号。
:interactive value次要模式默认为交互式命令。若 value 为 nil,则取消交互性。若 value 是符号列表,则用于说明该次要模式适用于哪些主模式。
其他所有关键字参数会直接传递给为变量 mode 生成的 defcustom。
See 定义自定义变量 可查看这些关键字及其取值的说明。
名为 mode 的命令首先执行标准操作,如设置同名变量,随后执行 body 中的表达式(如有)。
接着运行模式钩子变量 mode-hook,最后执行 :after-hook 中的表达式。
(注意:无论模式开启还是关闭,上述所有步骤包括运行钩子都会执行。)
初始化值必须为 nil,除非满足以下情况:(1) 该模式已预载入 Emacs;或 (2) 即使加载时未经用户请求就启用模式也不会产生任何问题。
例如,若该模式仅在其他功能启用时才生效,且届时必然已加载,那么默认启用是无害的。但这些均属于特殊情况。通常情况下,初始化值必须为 nil。
以下是使用 define-minor-mode 的示例:
(define-minor-mode hungry-mode "切换饥饿删除模式。 交互式无参调用时切换模式状态。 正前缀参数开启模式,其他前缀参数关闭模式。 在 Lisp 中调用时,无参或 nil 开启模式,`toggle' 切换状态。 启用饥饿删除模式时,控制删除键会删除前方所有空白字符,仅保留最后一个。 参见命令 \\[hungry-electric-delete]。" ;; 初始值 nil ;; 模式行指示器 " Hungry" ;; 次要模式按键绑定 '(([C-backspace] . hungry-electric-delete)))
这段代码定义了名为“饥饿删除模式”的次要模式、用于切换它的命令 hungry-mode、标识模式是否启用的变量 hungry-mode,以及模式启用时生效的按键映射变量 hungry-mode-map。
它为 C-DEL 设置了按键绑定。示例中没有 body 表达式——很多次要模式都不需要。
下面是等效的另一种写法:
(define-minor-mode hungry-mode
"Toggle Hungry mode.
...rest of documentation as before..."
;; The initial value.
:init-value nil
;; The indicator for the mode line.
:lighter " Hungry"
;; The minor mode bindings.
:keymap
'(([C-backspace] . hungry-electric-delete)
([C-M-backspace]
. (lambda ()
(interactive)
(hungry-electric-delete t)))))
该宏定义一个名为 global-mode 的全局切换命令,用于在所有(或部分,见下文)缓冲区中开启或关闭缓冲区局部次要模式 mode,同时执行 body 表达式。 它使用函数 turn-on 在缓冲区中开启次要模式;关闭时则以 −1 为参数调用 mode。 (函数 turn-on 独立存在,以便在无法确定是否应始终启用时自行判断是否启用次要模式。)
全局启用模式仅影响后续创建、且使用遵循 run-mode-hooks 规范的主模式的缓冲区。
未遵循该规范的主模式缓冲区不会启用该次要模式。
该宏会定义自定义选项 global-mode(see 自定义设置),可通过自定义界面切换以开启或关闭模式。
与 define-minor-mode 一样,应确保每次 Emacs 启动时都会执行 define-globalized-minor-mode 表达式,例如通过指定 :require 关键字。
可在 keyword-args 中使用 :group group 为该全局次要模式的变量指定自定义组。
默认情况下,标识模式是否启用的缓冲区局部变量与模式名相同。若并非如此,可使用 :variable variable 指定——部分次要模式使用其他变量存储状态。
通常,定义全局化次要模式时,也应同时定义非全局化版本,以便用户可在单个缓冲区中单独启用或禁用它。 这也允许用户在特定主模式中通过该模式的钩子禁用全局启用的次要模式。
若宏指定了 :predicate 关键字,则会创建一个用户选项,名称与全局模式变量相同,但末尾以 -modes 替代 -mode,即 global-modes。
该变量用于谓词函数,判断该次要模式是否应在特定主模式中激活,用户可自定义其值以控制模式生效范围。
:predicate 的合法取值(即其创建的用户选项合法取值)包括:
t(在所有主模式中使用)、nil(不在任何主模式中使用),或由模式名组成的列表,可在前面加上 not(如 (not mode-name …))。
这些元素可混合使用,如下例所示。
(c-mode (not mail-mode message-mode) text-mode)
含义为:“在继承自 c-mode 的模式中启用,不在继承自 message-mode 或 mail-mode 的模式中启用,但在继承自 text-mode 的模式中启用,其他模式均不启用”。
((not c-mode) t)
含义为:“不在继承自 c-mode 的模式中启用,其他所有模式均启用”。
(text-mode)
含义为:“仅在继承自 text-mode 的模式中启用,其他模式均不启用”。(末尾隐含一个 nil 元素。)
次要模式常会设置影响 Emacs 某些功能的缓冲区局部变量。当次要模式关闭时,模式应恢复这些变量之前的状态。
这个便捷宏可简化该操作:其行为与 setq-local 类似,但会返回一个对象,可用于将这些值恢复为之前的取值/状态(通过配套函数 buffer-local-restore-state)。
每个 Emacs 窗口(迷你缓冲区窗口除外)底部通常都有一条模式行,用于显示窗口中所展示缓冲区的状态信息。模式行包含与缓冲区相关的各类信息,例如缓冲区名称、关联文件、递归编辑层级,以及主模式和次要模式。窗口还可以拥有 表头行(header line) 和 标签行(tab line),它们与模式行类似,但出现在窗口顶部。
本节介绍如何控制模式行、表头行与标签行的内容。之所以将其放在本章,是因为模式行中显示的大部分内容都与已启用的主模式和次要模式相关。
每个模式行的内容由缓冲区局部变量 mode-line-format 指定(see 模式行控制的顶层结构)。该变量保存一个模式行构造(mode line construct):一个控制缓冲区模式行显示内容的模板。header-line-format 和 tab-line-format 的值以相同方式指定缓冲区的表头行和标签行。同一缓冲区的所有窗口均使用相同的 mode-line-format、header-line-format 和 tab-line-format,除非为该窗口单独指定了对应的参数(see Window Parameters)。
出于效率考虑,Emacs 不会持续重新计算每个窗口的模式行和表头行。仅在必要场景下才会更新,例如修改窗口配置、切换缓冲区、对缓冲区进行缩窄/扩宽、滚动或修改缓冲区内容。如果你修改了 mode-line-format 或 header-line-format 所引用的任意变量(see 模式行中使用的变量),或其他影响文本显示的数据结构(see Emacs Display),应使用函数 force-mode-line-update 强制更新显示。
该函数强制 Emacs 在下一次重绘周期中,根据所有相关变量的最新值更新当前缓冲区的模式行和表头行。若可选参数 all 非 nil,则强制更新所有模式行和表头行。
该函数同时会强制更新菜单栏与框架标题。
当前选中窗口的模式行通常使用 mode-line-active 面孔以不同颜色显示,其他窗口的模式行则使用 mode-line-inactive 面孔。See Faces。
若需要在选中与非选中窗口的模式行之间实现更丰富的差异,可在 :eval 构造中使用该谓词函数。例如,若希望在选中窗口中以粗体显示缓冲区名称,在其他窗口中以斜体显示,可使用如下代码:
(setq-default mode-line-buffer-identification '(:eval (propertize "%12b" 'face (if (mode-line-window-selected-p) 'bold 'italic))))
部分模式会在模式行中放置大量内容,导致行尾元素被挤出右侧。若变量 mode-line-compact 非 nil,Emacs 可对模式行进行“压缩”,将连续多个空格合并为单个空格。若该变量值为 long,则仅在模式行宽度超过当前选中窗口时才执行压缩。(该计算为近似值,基于字符数量而非实际显示宽度。)该变量可设为缓冲区局部,仅对特定缓冲区的模式行进行压缩。
模式行的内容由一种名为 模式行构造(mode line construct) 的数据结构控制,该结构由列表、字符串、符号与数字组成,并保存在缓冲区局部变量中。每种数据类型对模式行的显示外观均有特定含义,详见下文。同一套数据结构也用于构造框架标题(see Frame Titles)、标题栏(see 窗口标题栏)与标签栏(see 窗口标签栏)。
模式行构造可以简单到只是一段固定文本字符串,但它通常会指定如何将固定字符串与变量值组合以生成最终文本。其中许多变量本身的值也被定义为模式行构造。
以下是各类数据类型作为模式行构造时的含义:
string ¶字符串作为模式行构造时会原样显示,除非其中包含 %-constructs。这类结构代表替换其他数据;参见 模式行中的 %-constucts。
如果字符串的部分内容带有 face 属性,它们会像缓冲区中的文本一样控制显示效果。任何不带有 face 属性的字符,默认使用 mode-line 或 mode-line-inactive 外观显示(see Standard Faces in The GNU Emacs Manual)。字符串中的 help-echo 与 keymap 属性具有特殊含义。See 模式行中的属性。
symbol符号作为模式行构造时代表其变量值。symbol 的值会替代该符号本身,作为模式行构造使用。但符号 t 与 nil 会被忽略,值未定义的符号同样会被忽略。
有一个例外:如果 symbol 的值是字符串,则会直接原样显示:其中的 % 构造不会被解析。
除非 symbol 被标记为风险变量(即其 risky-local-variable 属性非 nil),否则其值中指定的所有文本属性都会被忽略。这包括该符号值中字符串的文本属性,以及其中所有 :eval 与 :propertize 形式。(这样设计是出于安全考虑:非风险变量可从文件变量自动设置,无需向用户提示。)
(string rest…)(list rest…)首元素为字符串或列表的列表,表示递归处理所有元素并将结果拼接。这是最常见的模式行构造形式。(注意:出于效率考虑,模式行中显示字符串时对文本属性有特殊处理:仅考虑字符串首字符的文本属性,并将其应用于整个字符串。若需要带有不同文本属性的字符串,必须使用专用的 :propertize 模式行构造。)
(:eval form)首元素为符号 :eval 的列表,表示对 form 求值,并将结果作为字符串显示。请确保该求值过程不会加载任何文件,也不会调用 posn-at-point 或 window-in-direction 这类自身会触发模式行求值的函数,否则可能导致无限递归。
(:propertize elt props…)首元素为符号 :propertize 的列表,表示先递归处理模式行构造 elt,再将 props 指定的文本属性添加到结果中。参数 props 应由零个或多个 text-property 与 value 成对组成。如果 elt 本身或生成的字符串带有文本属性,该字符串的所有字符应具有相同属性,否则部分属性可能被 :propertize 移除。
(symbol then else)首元素为非关键字符号的列表表示条件判断。其含义取决于 symbol 的值。若 symbol 的值非 nil,则第二个元素 then 会被递归处理为模式行构造;否则第三个元素 else 会被递归处理。else 可以省略;此时若 symbol 的值为 nil 或未定义,该模式行构造不显示任何内容。
(width rest…)首元素为整数的列表,用于指定 rest 结果的截断或填充。剩余元素 rest 会被递归处理为模式行构造并拼接。当 width 为正数时,若结果宽度不足 width,则在右侧填充空格。当 width 为负数时,若结果宽度超过 −width,则从右侧截断至 −width 列。
例如,显示缓冲区内容位于窗口顶部上方百分比的常用写法是类似这样的列表:(-3 "%p")。
全局控制模式行的变量是 mode-line-format。
该变量的值是一个模式行构造,用于控制模式行的内容。它在所有缓冲区中始终为缓冲区局部变量。
如果在某个缓冲区中将此变量设为 nil,则该缓冲区不会显示模式行。(高度仅为一行的窗口同样不会显示模式行。)
mode-line-format 的默认值设计为使用其他变量的值,例如 mode-line-position 与 mode-line-modes (后者又会整合 mode-name 与 minor-mode-alist 等变量的值)。绝大多数模式无需直接修改 mode-line-format。对于大多数场景,只需修改 mode-line-format 直接或间接引用的部分变量即可。
若确实需要修改 mode-line-format 本身,新值应沿用默认值中出现的相同变量(see 模式行中使用的变量),而非复制其内容或以其他方式展示信息。这样一来,用户或 Lisp 程序(如 display-time 与各类主模式)通过修改这些变量所做的自定义设置依然有效。
以下是一个适用于 Shell 模式的假想 mode-line-format 示例(实际 Shell 模式并不会设置 mode-line-format):
(setq mode-line-format (list "-" 'mode-line-mule-info 'mode-line-modified 'mode-line-frame-identification "%b--"
;; 注意:此表达式在构造列表时求值。 ;; 它生成一个仅为字符串的模式行构造。 (getenv "HOST")
":"
'default-directory
" "
'global-mode-string
" %[("
'(:eval (format-time-string "%F"))
'mode-line-process
'minor-mode-alist
"%n"
")%]--"
'(which-function-mode ("" which-func-format "--"))
'(line-number-mode "L%l--")
'(column-number-mode "C%c--")
'(-3 "%p")))
(变量 line-number-mode、column-number-mode 与 which-function-mode 用于启用对应的次要模式;与通常情况一致,这些变量名同时也是对应次要模式的命令名。)
本节介绍被 mode-line-format 的标准值纳入模式行文本的变量。
这些变量本身并无特殊之处;如果修改 mode-line-format 的值以使用其他变量,
它们同样可以对模式行产生相同效果。但 Emacs 的多个模块在设置这些变量时,
均默认它们会控制模式行的相应部分;因此从实际使用角度来说,模式行必须使用这些变量。
另请参见 Optional Mode Line in The GNU Emacs Manual。
该变量保存用于显示语言环境、缓冲区编码系统以及当前输入法相关信息的模式行构造值。 See Non-ASCII Characters。
该变量保存用于显示当前缓冲区是否已被修改的模式行构造值。其默认值显示规则为: 缓冲区已修改时显示 ‘**’,未修改时显示 ‘--’, 只读时显示 ‘%%’,只读且已修改时显示 ‘%*’。
修改此变量不会强制刷新模式行。
该变量用于标识当前框架。在可显示多个框架的窗口系统下,其默认值显示为 " ";
在同一时间仅显示单个框架的普通终端上,则显示为 "-%F "。
该变量用于标识窗口中正在显示的缓冲区。其默认值显示缓冲区名称, 并使用空格填充至至少 12 列宽度。
该变量用于指示缓冲区中的当前位置。其默认值显示缓冲区百分比, 并可选择显示缓冲区大小、行号与列号。
该选项在 mode-line-position 中使用,其值同时指定要显示的缓冲区百分比
(可为 nil、"%o"、"%p"、"%P" 或 "%q" 之一,
see 模式行中的 %-constucts)以及用于填充或截断的宽度。
建议使用 customize-variable 工具设置该选项。
每个缓冲区均局部生效的变量 vc-mode,用于记录缓冲区访问的文件是否受版本控制,
以及具体的版本控制类型。其值为显示在模式行中的字符串,
无版本控制时为 nil。
该变量用于显示缓冲区的主模式与次要模式。其默认值还会显示递归编辑层级、 进程状态信息以及是否启用了缓冲区收缩。
该变量用于显示当前缓冲区的 default-directory 是否为远程路径。
该变量用于标识 emacsclient 框架。
在 mode-line-format 中,该符号之后的所有内容均会右对齐显示。
该变量精确控制 mode-line-format-right-align 将内容对齐到哪一侧。
以下三个变量在 mode-line-modes 中使用:
该缓冲区局部变量保存当前缓冲区主模式的 “友好” 名称。
每个主模式都应设置此变量,以便模式名称显示在模式行中。
其值不必是字符串,可以使用模式行构造中合法的任意数据类型(see 模式行的数据结构)。
若要计算最终在模式行中显示的模式名称字符串,可使用 format-mode-line
(see 模拟模式行格式化)。
该缓冲区局部变量保存与子进程交互的模式中,用于显示进程状态的模式行信息。
它会紧跟在主模式名称后显示,中间无空格。例如,在 *shell* 缓冲区中,
其值为 (":%s"),可让 Shell 随同主模式一起显示状态,形如:‘(Shell:run)’。
通常该变量的值为 nil。
该变量显示在模式行最前端。默认情况下,此构造直接显示在模式行开头, 但若存在内存耗尽提示信息,则该信息会优先显示。
该变量显示在模式行末尾。
用于显示杂项信息的模式行构造。默认情况下,它显示由 global-mode-string 指定的内容。
当启用 line-number-mode(see Optional Mode Line in The GNU Emacs Manual)时,
用于显示行号的格式串。格式中的 ‘%l’ 会被替换为当前行号。
当启用 column-number-mode(see Optional Mode Line in The GNU Emacs Manual)时,
用于显示列号的格式串。格式中的 ‘%c’ 会被替换为从 0 开始计数的列号,
‘%C’ 会被替换为从 1 开始计数的列号。
当同时启用 line-number-mode 与 column-number-mode 时,
用于显示行号与列号的格式串。格式符 ‘%l’、‘%c’ 与 ‘%C’ 的含义
参见前两个变量的说明。
该变量保存一个关联列表,其元素用于指定模式行如何标识某个次要模式已激活。
minor-mode-alist 中的每个元素应为一个包含两个元素的列表:
(minor-mode-variable mode-line-string)
更一般地,mode-line-string 可以是任意模式行构造。
当 minor-mode-variable 的值非 nil 时,它会显示在模式行中,否则不显示。
这些字符串建议以空格开头,避免与前后内容连在一起。按照惯例,
某个次要模式激活时,其对应的 minor-mode-variable 会被设为非 nil 值。
minor-mode-alist 本身并非缓冲区局部变量。
如果某个次要模式可在各缓冲区独立启用,则列表中对应的变量应设为缓冲区局部生效。
该变量保存一个模式行构造,默认情况下作为 mode-line-misc-info 的一部分显示在模式行中:
若启用了 which-function-mode,则显示在该次要模式信息之后;
否则显示在 mode-line-modes 之后。添加到此构造中的元素通常应以空格结尾
(以保证连续的 global-mode-string 元素正常显示)。
例如,命令 display-time 会将 global-mode-string 设置为引用变量
display-time-string,该变量保存包含时间与系统负载信息的字符串。
‘%M’ 构造会替换为 global-mode-string 的值。
默认模式行并未使用该构造,而是直接在 mode-line-misc-info 中使用此变量本身。
以下是 mode-line-format 默认值的简化版本。
实际默认值还会指定额外的文本属性。
("-"
mode-line-mule-info
mode-line-modified
mode-line-frame-identification
mode-line-buffer-identification
" " mode-line-position (vc-mode vc-mode) " "
mode-line-modes
(which-function-mode ("" which-func-format "--"))
(global-mode-string ("--" global-mode-string))
"-%-")
%-constucts ¶用作模式行构造的字符串可以使用特定的 %-constructs 来替换各类数据。
下面列出已定义的所有 %-constructs 及其含义。
除 ‘%%’ 以外的任意构造中,你都可以在 ‘%’ 后添加一个十进制整数 以指定最小字段宽度。如果实际内容宽度不足,会填充至该宽度。 纯数字型构造(‘c’、‘i’、‘I’、‘l’)会在左侧补空格, 其他类型则在右侧补空格。
%b当前缓冲区名称,通过 buffer-name 函数获取。
See Buffer Names。
%c光标所在列号,从窗口左边缘起以 0 开始计数。
%C光标所在列号,从窗口左边缘起以 1 开始计数。
%e当 Emacs 的 Lisp 对象内存即将耗尽时显示简短提示,否则为空。
%f访问的文件名,通过 buffer-file-name 函数获取。
See Buffer File Name。
%F所选框架的标题(仅在窗口系统下)或名称。 See Basic Parameters。
%i当前缓冲区可访问部分的大小,基本等价于 (- (point-max) (point-min))。
%I与 ‘%i’ 类似,但大小以更易读的方式显示,使用 ‘k’ 表示 10^3、 ‘M’ 表示 10^6、‘G’ 表示 10^9 等缩写形式。
%l光标所在行号,在缓冲区可访问范围内计数。
%M变量 global-mode-string 的值(默认是 mode-line-misc-info 的一部分)。
%n当启用收缩显示时显示 ‘Narrow’,否则为空(参见 Narrowing 中的 narrow-to-region)。
%o窗口在缓冲区(可见部分)中的 滚动进度(travel),即窗口顶部以上文本大小 占窗口外全部文本的百分比,或显示 ‘Top’、‘Bottom’、‘All’。
%p窗口 顶部 以上的缓冲区文本百分比,或 ‘Top’、‘Bottom’、‘All’。 注意默认模式行构造会将其截断为三个字符。
%P窗口 底部 以上的缓冲区文本百分比(包含窗口可见文本及顶部以上文本), 若缓冲区顶部在屏幕可见则附加 ‘Top’;或显示 ‘Bottom’、‘All’。
%q窗口 顶部 以上与 底部 以上的文本百分比,以 ‘-’ 分隔, 或显示 ‘All’。
%s当前缓冲区所属子进程的状态,通过 process-status 获取。
See Process Information。
%z键盘、终端及缓冲区编码系统的助记符。
%Z与 ‘%z’ 类似,但额外包含行尾格式信息。
%&缓冲区已修改时显示 ‘*’,否则显示 ‘-’。
%*缓冲区为只读时显示 ‘%’(参见 buffer-read-only);
缓冲区已修改时显示 ‘*’(参见 buffer-modified-p);
其余情况显示 ‘-’。See Buffer Modification。
%+缓冲区已修改时显示 ‘*’(参见 buffer-modified-p);
缓冲区为只读时显示 ‘%’(参见 buffer-read-only);
其余情况显示 ‘-’。仅在已修改的只读缓冲区下与 ‘%*’ 不同。
See Buffer Modification。
%@若缓冲区的 default-directory(see 文件名展开相关函数)位于远程主机,
显示 ‘@’,否则显示 ‘-’。
%[递归编辑层级深度指示(不计入小缓冲区层级):每级编辑显示一个 ‘[’。 See 递归编辑。
%]每个递归编辑层级显示一个 ‘]’(不计入小缓冲区层级)。
%-足够填满模式行剩余空间的短横线。
%%字符 ‘%’ 本身—用于在允许 % 构造的字符串中插入字面量 ‘%’。
%-Constructs ¶以下构造不再建议使用。
%m已废弃;请改用变量 mode-name。%m 构造存在缺陷,
当 mode-name 的值为非字符串类型的模式行构造时(例如 emacs-lisp-mode),
会生成空字符串。
部分文本属性在模式行中有效。face 属性影响文本外观;
help-echo 属性为文本关联帮助字符串;
keymap 属性可使文本支持鼠标交互。
为模式行中的文本指定文本属性有四种方式:
(:propertize elt props…) 构造,
为 elt 添加由 props 指定的文本属性。
:eval form 的列表,
并使 form 求值后返回带有文本属性的字符串。
你可以使用 keymap 属性指定键盘映射。
该键盘映射仅对鼠标点击有效;为其绑定字符键和功能键无效果,
因为无法将光标移入模式行。
当模式行引用的变量不具有非 nil 的 risky-local-variable 属性时,
该变量值中所设置或指定的任何文本属性都会被忽略。
原因是这类属性可能指定待调用的函数,而这些函数可能来自文件局部变量。
窗口可以在顶部显示一条标题栏(header line),就像它可以在底部显示模式行一样。标题栏的工作机制与模式行完全相同,只是它由
header-line-format 控制:
该变量对每个缓冲区局部有效,用于指定显示该缓冲区的窗口如何展示标题栏。其值的格式与 mode-line-format 一致
(see 模式行的数据结构)。
该变量通常为 nil,因此普通缓冲区不会显示标题栏。
如果在缓冲区中开启了 display-line-numbers-mode
(see display-line-numbers-mode in The GNU
Emacs Manual),缓冲区文本在显示时会根据行号所需的屏幕宽度自动缩进。
与之不同,标题栏文本不会自动缩进,因为标题栏从不显示行号,且标题栏内容也不一定与下方的缓冲区文本直接相关。
如果 Lisp 程序需要让标题栏文本与缓冲区文本对齐(例如缓冲区以列状数据展示,如同
tabulated-list-mode,see 表格列表模式),则应开启次要模式
header-line-indent-mode。
该缓冲区局部次要模式会跟踪屏幕上行号显示宽度的变化(行号宽度可能随窗口内显示的行号范围而改变),
并允许 Lisp 程序在行号宽度变化时始终保持标题栏文本与缓冲区文本对齐。
这类 Lisp 程序应在缓冲区中开启此模式,并在 header-line-format 中使用变量
header-line-indent 与 header-line-indent-width,以确保标题栏始终与文本缩进匹配。
该变量的值为一个空白字符串,在窗口显示的缓冲区中开启 header-line-indent-mode 时,
其宽度会始终与当前行号显示宽度保持一致。空格数量基于一个假设计算:标题栏文本所使用的字体(包括字号)
与框架默认字体相同;若该假设不成立,则应使用下文介绍的 header-line-indent-width。
该变量适用于简单场景:只需将标题栏整体缩进,使其与下方缓冲区文本对齐,只需将此变量值添加到实际标题栏文本前即可。
例如,如下 header-line-format 定义:
(setq header-line-format
`("" header-line-indent ,my-header-line))
其中 my-header-line 是生成标题栏实际内容的格式字符串,可确保标题栏文本始终与下方缓冲区文本保持相同缩进。
在窗口显示的缓冲区中开启 header-line-indent-mode 时,该变量的值会持续更新,
以框架标准字符宽度为单位,表示当前行号显示所占用的宽度。当 header-line-indent
灵活性不足时,可使用该变量实现标题栏文本与缓冲区文本的对齐。
例如,若标题栏使用的字体度量与默认字体不同,你的 Lisp 程序可将此变量值与
frame-char-width 返回值相乘(see Frame Font),计算出行号显示的像素宽度,
再在 header-line-format 的相关部分使用 :align-to 显示属性规范(see Specified Spaces)
以像素为单位对齐标题栏文本。
该函数返回 window 标题栏的像素高度。window 必须为活动窗口,默认为选中窗口。
高度仅一行的窗口永远不会显示标题栏。高度为两行的窗口无法同时显示模式行与标题栏; 若存在模式行,则不会显示标题栏。
窗口可以在顶部显示一条标签栏(tab line)。若标签栏与标题栏同时可见,标签栏会出现在标题栏上方。
标签栏的控制方式与模式行类似,只是由 tab-line-format 控制。与模式行不同,
标签栏通常仅用于显示标签列表(see Tab Line in The GNU Emacs Manual)
或窗口工具栏(see Window Tool Bar in The GNU Emacs Manual):
该变量对每个缓冲区局部有效,用于指定显示该缓冲区的窗口如何展示标签栏。其值的格式与
mode-line-format 一致(see 模式行的数据结构)。该变量通常为 nil,
因此普通缓冲区不会显示标签栏。
该函数返回 window 标签栏的像素高度。window 必须为活动窗口,默认为选中窗口。
你可以使用函数 format-mode-line 根据指定的模式行结构计算出模式行或标题栏中应显示的文本。
该函数按照 format 格式化一行文本,如同为 window 生成模式行,并以字符串形式返回文本。
参数 window 默认为选中窗口。若 buffer 非 nil,所有信息均取自 buffer;
默认情况下信息来自 window 所属的缓冲区。
返回的字符串通常带有与模式行一致的文本属性,包括字体、键盘映射等。
对于 format 未指定 face 属性的字符,会使用由 face 决定的默认值。
若 face 为 t,则表示使用 mode-line(窗口选中时)或 mode-line-inactive(未选中时)。
若 face 为 nil 或省略,则使用默认字体。若 face 为整数,
函数返回值将不包含任何文本属性。
你也可以将其他合法字体指定为 face 的值。指定后,该字体会为 format 未指定字体的字符提供 face 属性。
注意:将 mode-line、mode-line-inactive 或 header-line
作为 face 时,除返回格式化字符串外,还会使用对应字体的当前定义重新显示模式行或标题栏。
(其他字体不会触发重绘。)
例如,(format-mode-line header-line-format) 返回选中窗口标题栏中应显示的文本
(无标题栏时返回 "")。(format-mode-line header-line-format 'header-line)
返回相同文本,且每个字符携带其在标题栏中实际显示的字体属性,同时重绘标题栏。
大纲次要模式(Outline minor mode)是一种缓冲区局部次要模式,它会隐藏缓冲区的部分内容,仅保留标题行可见。 该次要模式可与其他主模式配合使用 (see Outline Minor Mode in the Emacs Manual)。
定义哪些行为标题行有两种方式:通过变量
outline-regexp 或 outline-search-function。
该变量是一个正则表达式。 任何行首能匹配此正则表达式的行都会被视为标题行。 在行内(而非左边缘)开始的匹配不计入有效匹配。
另一种方式是,当无法编写匹配标题行的正则表达式时, 可以定义一个函数来辅助大纲次要模式查找标题行。
变量 outline-search-function 指定该函数,它接受四个参数:
bound、move、backward 和 looking-at。
该函数完成两项任务:匹配当前标题行,以及查找下一个或上一个标题行。
若参数 looking-at 为非 nil,则当光标位于大纲标题行开头时,
函数应返回非 nil。
若参数 looking-at 为 nil,则使用前三个参数。
参数 bound 是一个缓冲区位置,作为搜索边界。
找到的匹配结果不得超出该位置。
若该值为 nil,则表示搜索至缓冲区可访问部分的末尾。
若参数 move 为非 nil,则搜索失败时应移动至搜索边界并返回 nil。
若参数 backward 为非 nil,则该函数应向后搜索上一个标题行。
该变量是一个无参函数,
应返回当前标题的层级。
无论你使用 outline-regexp 还是 outline-search-function,
该函数都是必需的。
若 Emacs 编译时包含 tree-sitter 支持, 当主模式设置了以下变量时,Emacs 可自动启用大纲次要模式。
该变量用于指示 Emacs 如何查找包含大纲标题的行。 它应为一个谓词函数,用于匹配标题行上的节点。
字体加锁模式(Font Lock mode)是一种缓冲区局部次要模式,
它会根据缓冲区中内容的语法角色,自动为特定部分附加 face(外观)属性。
其解析缓冲区的方式由主模式决定;
大多数主模式都会定义语法规则,指定在何种语境下使用何种外观。
本节说明如何为特定主模式自定义字体加锁模式。
字体加锁模式通过三种方式查找需要高亮的文本: 通过基于完整解析器的解析(通常借助外部库或程序)、 基于 Emacs 内置语法表的语法解析, 或是通过搜索(通常为正则表达式)。 若启用,基于解析器的字体渲染会优先执行 (see 基于解析器的字体锁定)。 随后执行语法渲染,用于识别注释与字符串常量并高亮。 基于搜索的渲染最后执行。
字体加锁功能基于若干基础函数实现。 每个函数都会调用对应变量所指定的函数。 这种间接方式允许主模式和次要模式修改该模式缓冲区中字体渲染的行为, 甚至可以将字体加锁机制用于与字体渲染无关的功能。 (这也是下文在描述函数功能时使用“应当”的原因: 模式可以通过自定义对应变量的值来实现完全不同的逻辑。) 下文提及的变量详见 字体锁定其他变量。
font-lock-fontify-buffer ¶该函数应当通过调用 font-lock-fontify-buffer-function
指定的函数,对当前缓冲区的可访问部分执行字体渲染。
font-lock-unfontify-buffer ¶用于关闭字体加锁模式时移除字体渲染效果。
调用 font-lock-unfontify-buffer-function 指定的函数。
font-lock-fontify-region beg end &optional loudly ¶应当对 beg 与 end 之间的区域执行字体渲染。
若 loudly 为非 nil,则渲染时应显示状态信息。
调用 font-lock-fontify-region-function 指定的函数。
font-lock-unfontify-region beg end ¶应当移除 beg 与 end 之间区域的字体渲染效果。
调用 font-lock-unfontify-region-function 指定的函数。
font-lock-flush &optional beg end ¶该函数应当将 beg 与 end 之间区域的字体渲染标记为过期。
若未指定或为 nil,beg 与 end 默认为缓冲区可访问部分的开头与结尾。
调用 font-lock-flush-function 指定的函数。
font-lock-ensure &optional beg end ¶该函数应当确保 beg 与 end 之间的区域已完成字体渲染。
可选参数 beg 与 end 默认为缓冲区可访问部分的开头与结尾。
调用 font-lock-ensure-function 指定的函数。
font-lock-debug-fontify ¶这是一个便捷命令,用于为某一模式开发字体加锁规则时使用,
不应在 Lisp 代码中调用。
它会重新计算所有相关变量,随后对整个缓冲区调用 font-lock-fontify-region。
有若干变量用于控制字体加锁模式如何高亮文本。
但主模式不应直接设置这些变量。
相反,它们应当将 font-lock-defaults 设置为缓冲区局部变量。
当字体加锁模式启用时,该变量的值会被用于设置其他所有相关变量。
该变量由各模式自行设置,用于指定该模式下文本的字体渲染方式。
设置后会自动变为缓冲区局部变量。
若其值为 nil,字体加锁模式不执行任何高亮。
若为非 nil,其值格式如下:
(keywords [keywords-only [case-fold [syntax-alist other-vars...]]])
第一个元素 keywords 间接指定 font-lock-keywords 的值,
用于控制基于搜索的字体渲染。
它可以是一个符号、变量或函数,其值为供 font-lock-keywords 使用的列表。
也可以是多个此类符号组成的列表,分别对应不同的字体渲染等级。
第一个符号指定‘模式默认’渲染等级,
下一个为等级 1,再下一个为等级 2,依此类推。
‘模式默认’等级通常与等级 1 相同,
在 font-lock-maximum-decoration 为 nil 时使用。
See 字体锁定级别。
第二个元素 keywords-only 指定变量 font-lock-keywords-only 的值。
若该元素省略或为 nil,则同时执行语法字体渲染(字符串与注释)。
若为非 nil,则不执行语法字体渲染。
See 语法字体锁定。
第三个元素 case-fold 指定 font-lock-keywords-case-fold-search 的值。
若为非 nil,字体加锁模式在基于搜索的渲染中忽略大小写。
第四个元素 syntax-alist 若为非 nil,
应当是形如 (char-or-string . string) 的 cons 单元格列表。
这些用于构建语法字体渲染所需的语法表,
生成的语法表保存在 font-lock-syntax-table 中。
若 syntax-alist 省略或为 nil,
语法字体渲染使用 syntax-table 函数返回的语法表。
See Syntax Table Functions。
其余所有元素(若有)统称为 other-vars。
每个元素格式为 (variable . value),
意为将 variable 设为缓冲区局部变量并赋值为 value。
你可以通过这些 other-vars 设置前五个元素无法控制的、影响字体渲染的其他变量。
See 字体锁定其他变量。
若你的模式通过显式添加 font-lock-face 属性实现文本渲染,
可以为 font-lock-defaults 指定 (nil t) 以关闭所有自动字体渲染。
但这并非必需;可以同时使用 font-lock-face 属性渲染部分内容,
并为文本其他部分配置自动渲染。
直接控制基于搜索的字体高亮的变量是
font-lock-keywords,该变量通常通过 font-lock-defaults 中的
keywords 元素指定。
该变量的值为需要高亮的关键字列表。Lisp
程序不应直接设置此变量。通常情况下,该值由字体锁定模式根据
font-lock-defaults 中的 keywords 元素自动设置。
也可以通过函数 font-lock-add-keywords 和
font-lock-remove-keywords 修改其值(see 自定义基于搜索的字体高亮)。
font-lock-keywords 中的每个元素都指定了如何查找特定文本
以及如何对其进行高亮。字体锁定模式会依次处理
font-lock-keywords 中的各个元素,并对每个元素查找并处理所有匹配项。
通常,一段文本一旦已经完成高亮,就不会被同一段落中后续的匹配覆盖;
但你可以通过 subexp-highlighter 中的 override 元素指定不同行为。
font-lock-keywords 中的每个元素应采用以下形式之一:
regexp使用 font-lock-keyword-face 高亮 regexp 的所有匹配项。例如:
;; Highlight occurrences of the word ‘foo’
;; using font-lock-keyword-face.
"\\<foo\\>"
编写此类正则表达式时需谨慎;拙劣的匹配模式会显著降低运行速度!
函数 regexp-opt(see Regular Expression Functions)可用于生成匹配多个关键字的最优正则表达式。
function通过调用 function 查找文本,并使用
font-lock-keyword-face 高亮其找到的匹配项。
调用 function 时会传入一个参数,即搜索的边界位置;
函数应从当前点开始搜索,且不超出该边界。
若搜索成功则返回非 nil,并设置匹配数据以描述找到的匹配项。
返回 nil 表示搜索失败。
字体高亮会以相同边界、在前一次调用结束的位置反复调用 function,直到 function 失败为止。 失败时,function 无需以特定方式重置当前点。
(matcher . subexp)在这类元素中,matcher 为正则表达式或函数(同上)。 其 CDR 部分 subexp 指定应高亮 matcher 的哪个子表达式 (而非 matcher 匹配的整个文本)。
;; Highlight the ‘bar’ in each occurrence of ‘fubar’,
;; using font-lock-keyword-face.
("fu\\(bar\\)" . 1)
(matcher . facespec)在这类元素中,facespec 是一个表达式,其值指定用于高亮的外观。 最简单的情况下,facespec 是一个 Lisp 变量(符号),其值为外观名称。
;; Highlight occurrences of ‘fubar’,
;; using the face which is the value of fubar-face.
("fubar" . fubar-face)
不过,facespec 也可以求值为如下形式的列表:
(subexp (face face prop1 val1 prop2 val2...))
用于为匹配的文本指定外观 face 以及各种附加文本属性。
如果这样做,务必将通过该方式设置的其他文本属性名加入
font-lock-extra-managed-props 的值中,以便这些属性在不再适用时也能被清除。
或者,你可以将变量 font-lock-unfontify-region-function
设置为一个负责清除这些属性的函数。See 字体锁定其他变量。
(matcher . subexp-highlighter)在这类元素中,subexp-highlighter 是一个列表, 用于指定如何高亮 matcher 找到的匹配项。 其形式为:
(subexp facespec [override [laxmatch]])
其 CAR 部分 subexp 是一个整数,指定高亮匹配项中的哪个子表达式 (0 表示整个匹配文本)。第二个子元素 facespec 是一个表达式,其值指定外观,同上所述。
subexp-highlighter 中的最后两个值 override 和 laxmatch
是可选标志。若 override 为 t,
则该元素可以覆盖 font-lock-keywords 中先前元素已设置的高亮。
若为 keep,则仅对尚未被其他元素高亮的字符进行高亮。
若为 prepend,则 facespec 指定的外观会添加到
font-lock-face 属性的开头。若为 append,
则外观添加到 font-lock-face 属性的末尾。
若 laxmatch 为非 nil,表示当 matcher
中不存在编号为 subexp 的子表达式时不报错。
显然,对应子表达式的高亮不会生效,但其他子表达式
(以及其他正则表达式)的高亮仍会继续。若 laxmatch 为 nil
且指定子表达式缺失,则会抛出错误并终止基于搜索的高亮。
以下是此类元素的若干示例及其作用:
;; 高亮 ‘foo’ 或 ‘bar’ 的出现,使用 ;;foo-bar-face,即使它们已被高亮。 ;;foo-bar-face应为值为外观的变量。 ("foo\\|bar" 0 foo-bar-face t) ;; 高亮函数fubar-match找到的每个匹配项中的第一个子表达式, ;; 使用fubar-face的值所表示的外观。 (fubar-match 1 fubar-face)
(matcher . anchored-highlighter)在这类元素中,anchored-highlighter 指定如何高亮 matcher 匹配项之后的文本。因此 matcher 找到的匹配项会作为锚点,供 anchored-highlighter 中定义的后续搜索使用。anchored-highlighter 是如下形式的列表:
(anchored-matcher pre-form post-form subexp-highlighters...)
其中,anchored-matcher 与 matcher 类似, 可以是正则表达式或函数。在找到 matcher 的匹配项后, 当前点位于匹配项末尾。随后,字体锁定模式求值 pre-form, 接着搜索 anchored-matcher 的匹配项并使用 subexp-highlighters 进行高亮。subexp-highlighter 的定义同上。最后,字体锁定模式求值 post-form。
pre-form 和 post-form 可用于在使用 anchored-matcher 之前进行初始化、之后进行清理。 典型用法是在开始 anchored-matcher 之前, 通过 pre-form 将当前点移动到 matcher 匹配项的相对位置。post-form 则可用于在恢复 matcher 搜索之前移回原位。
字体锁定模式在求值 pre-form 后, 不会在行尾之外搜索 anchored-matcher。 但如果 pre-form 求值后返回的缓冲区位置大于当前点位置, 则以该返回位置作为搜索边界。通常不建议返回超出行尾的位置; 也就是说,anchored-matcher 的搜索不应跨行。
例如:
;; Highlight occurrences of the word ‘item’ following
;; an occurrence of the word ‘anchor’ (on the same line)
;; in the value of item-face.
("\\<anchor\\>" "\\<item\\>" nil nil (0 item-face))
此处 pre-form 和 post-form 均为 nil。
因此对 ‘item’ 的搜索从 ‘anchor’
匹配项的末尾开始,而后续 ‘anchor’ 的搜索
则从 ‘item’ 搜索结束的位置继续。
(matcher highlighters…)这类元素为单个 matcher 指定多个 highlighter 列表。 highlighter 列表可以是上述 subexp-highlighter 或 anchored-highlighter 类型。
例如:
;; Highlight occurrences of the word ‘anchor’ in the value ;; ofanchor-face, and subsequent occurrences of the word ;; ‘item’ (on the same line) in the value ofitem-face. ("\\<anchor\\>" (0 anchor-face) ("\\<item\\>" nil nil (0 item-face)))
(eval . form)此处 form 是一个表达式,会在缓冲区首次使用此
font-lock-keywords 值时求值。
其结果应为本表格中所列形式之一。
警告: 不要设计跨行匹配文本的
font-lock-keywords 元素;此类方式无法可靠工作。
详情参见 see 多行字体锁定结构。
你可以在 font-lock-defaults 中使用 case-fold
指定 font-lock-keywords-case-fold-search 的值,
该变量决定基于搜索的高亮是否忽略大小写。
非 nil 表示为 font-lock-keywords
进行的正则表达式匹配应忽略大小写。
你可以使用 font-lock-add-keywords 为主模式添加额外的
基于搜索的高亮规则,使用 font-lock-remove-keywords
移除规则。你也可以自定义 font-lock-ignore 选项,
有选择地禁用匹配特定条件的关键字高亮规则。
该函数为当前缓冲区或主模式 mode 添加高亮关键字 keywords。
参数 keywords 应为格式与变量 font-lock-keywords 相同的列表。
若 mode 是代表主模式命令名的符号(如 c-mode),
则效果是在 mode 中启用字体锁定模式时,
会将 keywords 添加到 font-lock-keywords。
传入非 nil 的 mode 仅适合在 ~/.emacs 文件中使用。
若 mode 为 nil,则该函数将 keywords
添加到当前缓冲区的 font-lock-keywords。
这种调用方式通常用于模式钩子函数。
默认情况下,keywords 会添加到 font-lock-keywords 的开头。
若可选参数 how 为 set,
则用其替换 font-lock-keywords 的值。
若 how 为其他非 nil 值,
则添加到 font-lock-keywords 的末尾。
部分模式为额外高亮模式提供专用支持。
例如参见变量 c-font-lock-extra-types、
c++-font-lock-extra-types 和 java-font-lock-extra-types。
警告: 主模式命令在任何情况下都不应直接或间接调用
font-lock-add-keywords,除非通过其模式钩子。
(否则会导致部分次要模式行为异常。)
主模式应通过设置 font-lock-keywords
配置基于搜索的高亮规则。
该函数从当前缓冲区或主模式 mode 的
font-lock-keywords 中移除 keywords。
与 font-lock-add-keywords 相同,
mode 应为主模式命令名或 nil。
所有适用于 font-lock-add-keywords 的注意事项与要求同样适用。
参数 keywords 必须与对应 font-lock-add-keywords
中使用的完全一致。
例如,以下代码为 C 模式添加两个高亮规则: 一个用于高亮单词 ‘FIXME’(即使在注释中), 另一个用于将单词 ‘and’、‘or’ 和 ‘not’ 作为关键字高亮。
(font-lock-add-keywords 'c-mode
'(("\\<\\(FIXME\\):" 1 font-lock-warning-face prepend)
("\\<\\(and\\|or\\|not\\)\\>" . font-lock-keyword-face)))
该示例仅对 C 模式本身生效。若要将相同规则同时应用于 C 模式及其所有派生模式,可改用:
(add-hook 'c-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("\\<\\(FIXME\\):" 1 font-lock-warning-face prepend)
("\\<\\(and\\|or\\|not\\)\\>" .
font-lock-keyword-face)))))
该选项定义有选择地禁用特定字体锁定关键字导致的高亮的条件。
若为非 nil,其值为如下形式的元素列表:
(symbol condition ...)
其中 symbol 是一个符号,通常为主模式或次要模式。
当 symbol 被绑定且值为非 nil 时,
该符号对应列表中的后续 condition 生效。
对模式符号而言,这表示当前主模式派生自该模式,
或该次要模式在缓冲区中已启用。
当某个 condition 生效时,
所有由匹配该条件的 font-lock-keywords 元素触发的高亮都会被禁用。
每个 condition 可以是以下之一:
该条件匹配所有引用该符号的字体锁定关键字元素。
通常为外观,但也可以是 font-lock-keywords
列表元素引用的任意符号。符号中可包含通配符:
* 匹配符号名中的任意字符串,
? 匹配单个字符,
而 [char-set](其中 char-set 为一个或多个字符组成的字符串)
匹配集合中的单个字符。
该条件匹配所有 matcher 为能匹配该字符串的正则表达式的 字体锁定关键字元素。换句话说, 该条件匹配用于高亮该字符串的字体锁定规则。 因此该字符串可以是你希望禁用高亮的特定程序关键字。
(pred function)This condition matches any element of Font Lock keywords for which
function, when called with the element as the argument, returns
non-nil.
(pred function)该条件匹配所有以元素为参数调用 function
并返回非 nil 的字体锁定关键字元素。
(not condition)当 condition 不匹配时匹配。
(and condition …)当所有 condition 均匹配时匹配。
(or condition …)当至少一个 condition 匹配时匹配。
(except condition)该条件仅可用于顶层或 or 子句内部。
用于撤销同一层级中先前匹配条件的效果。
举一个设置示例:
(setq font-lock-ignore
'((prog-mode font-lock-*-face
(except help-echo))
(emacs-lisp-mode (except ";;;###autoload)")
(whitespace-mode whitespace-empty-at-bob-regexp)
(makefile-mode (except *))))
逐行说明如下:
help-echo 文本属性的关键字。
whitespace-mode(次要模式)时,
同时不高亮缓冲区开头的空行。
本节介绍主模式可通过 font-lock-defaults 中的
other-vars 进行设置的其他变量(see Font Lock 基础)。
若该变量非 nil,则其值应为一个无参函数,
用于为命令 M-x font-lock-fontify-block 选择一段外围文本范围以重新高亮。
该函数应通过设置区域来告知所选范围。
合适的选择是大小足以获得正确高亮效果、但又不至于过大而导致重新高亮变慢的文本范围。
典型取值:编程模式使用 mark-defun,文本模式使用 mark-paragraph。
该变量指定由字体锁定模式管理的额外属性(除 font-lock-face 之外)。
它由 font-lock-default-unfontify-region 使用,该函数默认仅管理 font-lock-face 属性。
若你希望字体锁定同时管理其他属性,必须在 font-lock-keywords 的 facespec 中指定这些属性,
并将其加入本列表。See 基于搜索的字体高亮。
用于对整个缓冲区执行高亮的函数。默认值为 font-lock-default-fontify-buffer。
用于取消整个缓冲区高亮的函数。在关闭字体锁定模式时使用。
默认值为 font-lock-default-unfontify-buffer。
用于对指定区域执行高亮的函数。它接收两个参数:区域起始位置和结束位置,
以及可选的第三个参数 verbose。若 verbose 非 nil,
函数应打印状态信息。默认值为 font-lock-default-fontify-region。
用于取消指定区域高亮的函数。它接收两个参数:区域起始位置和结束位置。
默认值为 font-lock-default-unfontify-region。
用于声明某区域的高亮已过期的函数。它接收两个参数:区域起始位置和结束位置。
该变量的默认值为 font-lock-after-change-function。
用于确保当前缓冲区指定区域已完成高亮的函数。
它接收两个参数:区域起始位置和结束位置。
该变量的默认函数会在缓冲区未高亮时调用 font-lock-default-fontify-buffer,
效果是确保缓冲区所有可访问部分均被高亮。
该函数告知字体锁定模式:在需要对当前缓冲区某部分执行高亮或重新高亮时,
运行 Lisp 函数 function。
它会在调用默认高亮函数之前先调用 function,并传入两个参数 start 和 end,
指明需要高亮或重新高亮的区域。
若 function 自身执行了高亮,可返回形如 (jit-lock-bounds beg . end) 的列表,
表明其实际高亮的区域边界;即时(“JIT”)字体锁定会利用该信息优化后续重绘周期,
以及后续调用 function 时传入的缓冲区文本区域。
可选参数 contextual 非 nil 时,会强制字体锁定模式始终对缓冲区中语法相关的部分重新高亮,
而不仅是修改过的行。该参数通常可以省略。
当字体锁定在缓冲区启用时,若 font-lock-keywords-only(see 语法字体锁定)值为 nil,
则会以非 nil 的 contextual 调用此函数。
若 function 此前已通过 jit-lock-register 注册为高亮函数,
本函数将取消其注册。
这是一个次要模式,用于辅助调试由即时字体锁定运行的代码。
启用该模式后,即时字体锁定在重绘周期中原本会抑制 Lisp 错误而运行的大部分代码,
将改为由定时器执行。因此该模式允许使用 debug-on-error(see 发生错误时进入调试器)
和 Edebug(see Edebug)等调试工具查找并修复字体锁定代码及其他由即时字体锁定运行的代码中的问题。
开发与调试字体锁定时另一个有用的命令是 font-lock-debug-fontify,
参见 Font Lock 基础。
部分主模式提供三种不同的高亮级别。
你可以在 font-lock-defaults 中为 keywords 使用符号列表来定义多个级别。
每个符号对应一种高亮级别,最终由用户选择其中一级,
通常通过设置 font-lock-maximum-decoration 实现(see Font Lock in the GNU Emacs Manual)。
所选级别的符号值会用于初始化 font-lock-keywords。
以下是定义高亮级别的通用约定:
诸如 list-buffers 和 occur 等部分主模式会以编程方式构造缓冲区文本。
它们支持字体锁定模式最简单的方式是:在向缓冲区插入文本时直接指定文本的外观。
实现方法是通过特殊文本属性 font-lock-face 为文本指定外观(see Properties with Special Meanings)。
启用字体锁定模式时,该属性与 face 属性一样控制显示效果;
禁用字体锁定模式时,font-lock-face 对显示无影响。
一个模式可以对部分文本使用 font-lock-face,同时也使用标准字体锁定机制。
但如果该模式不使用标准字体锁定机制,则不应设置变量 font-lock-defaults。
这种情况下 face 属性不会被覆盖,因此直接使用 face 属性也可行。
不过通常更推荐使用 font-lock-face,
因为它允许用户通过开关 font-lock-mode 控制高亮,
且无论模式是否使用字体锁定机制,代码都能正常工作。
字体锁定模式可使用任意外观进行高亮,但 Emacs 专门定义了若干外观供字体锁定高亮文本使用。 这些字体锁定外观如下所列。 主模式也可在字体锁定模式之外用它们进行语法高亮(see 主模式编码规范)。
这些符号既是外观名,也是变量,其默认值为符号自身。
例如 font-lock-comment-face 的默认值即为 font-lock-comment-face。
下列外观按典型用途说明,并按醒目程度从高到低排列。 若某模式的语法分类与用途描述不完全匹配,可按该顺序作为分配依据。
font-lock-warning-face ¶用于异常结构(例如 Emacs Lisp 符号中未转义的易混淆引号,如 ‘‘foo’), 或会大幅改变其他文本含义的结构,如 Emacs Lisp 中的 ‘;;;###autoload’ 和 C 语言中的 ‘#error’。
font-lock-function-name-face ¶用于被定义或声明的函数名。
font-lock-function-call-face ¶用于被调用的函数名。该外观默认继承自 font-lock-function-name-face。
font-lock-variable-name-face ¶用于被定义或声明的变量名。
font-lock-variable-use-face ¶用于被引用的变量名。该外观默认继承自 font-lock-variable-name-face。
font-lock-keyword-face ¶用于具有特殊语法意义的关键字,如 C 语言中的 ‘for’ 和 ‘if’。
font-lock-comment-face ¶用于注释。
font-lock-comment-delimiter-face ¶用于注释定界符,如 C 语言中的 ‘/*’ 和 ‘*/’。
在多数终端上,该外观继承自 font-lock-comment-face。
font-lock-type-face ¶用于用户自定义数据类型名。
font-lock-constant-face ¶用于常量名,如 C 语言中的 ‘NULL’。
font-lock-builtin-face ¶用于内置函数名。
font-lock-preprocessor-face ¶用于预处理指令。该外观默认继承自 font-lock-builtin-face。
font-lock-string-face ¶用于字符串常量。
font-lock-doc-face ¶用于程序代码中以特殊格式注释或字符串嵌入的文档内容。
该外观默认继承自 font-lock-string-face。
font-lock-doc-markup-face ¶用于使用 font-lock-doc-face 的文本中的标记元素。
通常用于代码内嵌文档中的标记结构,遵循 Haddock、Javadoc 或 Doxygen 等规范。
该外观默认继承自 font-lock-constant-face。
font-lock-negation-char-face ¶用于容易被忽略的取反字符。
font-lock-escape-face ¶用于字符串中的转义序列。
该外观默认继承自 font-lock-regexp-grouping-backslash。
以下为 Python 示例,其中使用了转义序列 \n:
print('Hello world!\n')
font-lock-number-face ¶用于数字。
font-lock-operator-face ¶用于运算符。
font-lock-property-name-face ¶用于对象属性,如结构体中字段的声明。
该外观默认继承自 font-lock-variable-name-face。
font-lock-property-use-face ¶用于对象属性的使用,如结构体字段的访问。
该外观默认继承自 font-lock-property-name-face。
示例:
typedef struct
{
int prop;
// ^ property
} obj;
int main()
{
obj o;
o.prop = 3;
// ^ property
}
font-lock-punctuation-face ¶用于括号、定界符等标点符号。
font-lock-bracket-face ¶用于各类括号(如 ()、[]、{})。
该外观默认继承自 font-lock-punctuation-face。
font-lock-delimiter-face ¶用于语句定界符(如 ;、:、,)。
该外观默认继承自 font-lock-punctuation-face。
font-lock-misc-punctuation-face ¶用于非括号、非定界符的其他标点。
该外观默认继承自 font-lock-punctuation-face。
语法字体高亮通过语法表(see Syntax Tables)查找并高亮语法相关的文本。
若启用,它会在基于搜索的高亮之前运行。变量
font-lock-syntactic-face-function(见下文说明)决定对哪些语法结构进行高亮。
有多个变量会影响语法高亮,你应当通过 font-lock-defaults 进行设置(see Font Lock 基础)。
每当字体锁定模式对一段文本执行语法高亮时,都会先调用
syntax-propertize-function 指定的函数。主模式可以利用它来应用
syntax-table 文本属性,以便在特殊场景下覆盖缓冲区自身的语法表。
See Syntax Properties。
若该变量值为非 nil,字体锁定将**不执行语法高亮**,
仅基于 font-lock-keywords 做基于搜索的高亮。
该值通常由字体锁定模式根据 font-lock-defaults 中的
keywords-only 元素自动设置。若值为 nil,
字体锁定会调用 jit-lock-register(see 字体锁定其他变量),
以便在某行被修改后,自动重新高亮缓冲区后续文本,以反映修改带来的新语法上下文。
若只想使用**语法高亮**,应将此变量设为非 nil,
同时将 font-lock-keywords 设为 nil(see Font Lock 基础)。
该变量保存用于高亮注释和字符串的语法表。
它通常由字体锁定模式根据 font-lock-defaults 中的
syntax-alist 元素设置。若值为 nil,
语法高亮将使用缓冲区自身的语法表(即函数 syntax-table 返回的值;see Syntax Table Functions)。
若该变量非 nil,其值应为一个函数,
用于为给定的语法元素(字符串或注释)决定使用哪种外观。
该函数接收一个参数:由 parse-partial-sexp 返回的当前点解析状态,
并应返回一个外观。默认函数对注释返回 font-lock-comment-face,
对字符串返回 font-lock-string-face(see 字体锁定专用外观)。
该变量通常通过 font-lock-defaults 中的 “other” 元素设置:
(setq-local font-lock-defaults
`(,python-font-lock-keywords
nil nil nil
(font-lock-syntactic-face-function
. python-font-lock-syntactic-face-function)))
通常情况下,font-lock-keywords 中的元素**不应跨行匹配**;
这种方式无法可靠工作,因为字体锁定一般只扫描缓冲区的一部分,
可能会错过从扫描起始行边界开始的多行结构。(扫描通常从行首开始。)
让匹配多行结构的元素正常工作包含两个方面:正确的 识别(identification) 与正确的 重新高亮(rehighlinghting)。 前者指字体锁定能够找到所有多行结构;后者指当多行结构被修改时, 字体锁定能正确重新高亮所有相关文本—例如,原本属于多行结构的文本不再属于该结构时。 这两方面紧密相关,通常修复其中一个似乎会让另一个也正常工作。 但要获得可靠结果,必须显式处理这两方面。
确保正确识别多行结构有三种方法:
font-lock-extend-region-functions 添加函数,
由其完成**识别**并扩展扫描范围,使扫描文本不会在多行结构中间开始或结束。
font-lock-fontify-region-function 扩展扫描范围,
避免扫描在多行结构中间起止。
font-lock-multiline 属性,
指示字体锁定不要在该结构中间起止扫描。
实现多行结构重新高亮有若干方法:
font-lock-multiline 属性。
若结构任意部分被修改,将重新高亮整个结构。
某些场景下可通过设置变量 font-lock-multiline 自动实现,详见该变量说明。
jit-lock-contextually 已启用并依赖其工作。
它只会重新高亮修改位置之后的部分,并略有延迟。
该方式仅在多行结构各部分的高亮**不依赖后续行文本**时有效。
由于 jit-lock-contextually 默认启用,这是一种很实用的方案。
jit-lock-defer-multiline 属性。
该方式仅在使用 jit-lock-contextually 时生效,重新高亮同样有延迟,
但与 font-lock-multiline 类似,可处理高亮依赖后续行的情况。
syntax-multiline 文本属性。
最常见的场景是:‘FOO’ 上应用的语法属性依赖后续文本 ‘BAR’;
通过在整个 ‘FOO...BAR’ 上添加该属性,可确保 ‘BAR’ 发生变化时,
‘FOO’ 的语法属性也会重新计算。
注意:要使其生效,模式需要将 syntax-propertize-multiline
加入 syntax-propertize-extend-region-functions。
确保多行字体锁定结构能可靠重新高亮的一种方法,是为其添加文本属性
font-lock-multiline。凡是属于多行结构的文本,都应当存在该属性且值为非 nil。
当字体锁定即将高亮一段文本范围时,会先按需扩展该范围的边界,
使其不会落在带有 font-lock-multiline 属性的文本中间。
随后它会移除该范围内所有的 font-lock-multiline 属性,再执行高亮。
高亮规则(主要是 font-lock-keywords)必须在每次合适的时候重新设置该属性。
警告:不要在大片文本上使用 font-lock-multiline 属性,
否则会导致重新高亮速度变慢。
若变量 font-lock-multiline 设为 t,
字体锁定会尝试自动为多行结构添加 font-lock-multiline 属性。
但这并非通用解决方案,因为它会在一定程度上降低字体锁定的速度。
它可能会遗漏某些多行结构,或者把属性设置得过大或过小。
对于 matcher 为函数的元素,该函数应确保子匹配 0 覆盖整个相关多行结构,
即便只会高亮其中一小部分。很多时候直接手动添加
font-lock-multiline 属性会更简单可靠。
font-lock-multiline 属性的作用是确保正确重新高亮;
它并不会自动识别新的多行结构。要识别这些结构,
要求字体锁定模式每次处理足够大的文本块。很多情况下这会偶然满足,
让人感觉多行结构仿佛“神奇地”正常工作。如果你将
font-lock-multiline 变量设为非 nil,
这种错觉会更明显,因为那些被找到的结构之后的高亮会被正确更新。
但这并不可靠。
要可靠地找到多行结构,你必须要么在字体锁定模式处理之前
手动为文本加上 font-lock-multiline 属性,
要么使用 font-lock-fontify-region-function。
当缓冲区被修改时,字体锁定默认重新高亮的区域是覆盖修改位置的最小整行序列。 虽然这在大多数情况下工作良好,但某些场景下并不适用—— 例如,某次修改改变了更早行上文文本的语法含义。
你可以通过设置以下变量来扩大(甚至缩小)需要重新高亮的区域:
这个缓冲区局部变量要么为 nil,要么是一个函数,
供字体锁定模式调用以确定需要扫描并高亮的区域。
该函数接收三个参数:来自 after-change-functions 的标准参数
beg、end 和 old-len(see Change Hooks)。
它应当返回一个 cons 对,表示要高亮区域的起始和结束缓冲区位置(按此顺序),
或返回 nil(表示按标准方式选择区域)。
该函数需要保持当前点、匹配数据和当前限制不变。
其返回的区域可以在行中间开始或结束。
由于该函数在每次缓冲区修改后都会调用,因此必须保证足够高效。
除了简单的语法字体锁定和基于正则表达式的字体锁定外, Emacs 还借助解析器提供完整的语法字体锁定能力。 目前,Emacs 使用 tree-sitter 库实现这一功能(see Parsing Program Source)。
基于解析器的字体锁定与其他字体锁定机制并不互斥。 默认情况下,若启用,基于解析器的字体会先运行,替代语法字体锁定, 之后再运行基于正则表达式的字体锁定。
尽管基于解析器的字体锁定与基于正则表达式的字体锁定不共用同一套自定义变量,
但采用了相似的自定义方案。font-lock-keywords 对应的 tree-sitter 变量是
treesit-font-lock-settings。
通常,tree-sitter 高亮的工作流程如下:
font-lock-keyword 的节点会使用
font-lock-keyword-face 进行高亮。
关于查询、模式和捕获名称的更多信息,参见 Pattern Matching Tree-sitter Nodes。
要设置 tree-sitter 高亮,主模式应先使用
treesit-font-lock-rules 的输出设置
treesit-font-lock-settings,然后调用
treesit-major-mode-setup。
该函数用于设置 treesit-font-lock-settings。
它负责编译查询和其他后处理,并输出一个
treesit-font-lock-settings 可接受的值。示例如下:
(treesit-font-lock-rules :language 'javascript :feature 'constant :override t '((true) @font-lock-constant-face (false) @font-lock-constant-face) :language 'html :feature 'script "(script_element) @font-lock-builtin-face")
该函数接收一系列 query-spec,每个 query-spec 是在一个 query 前面加上一个或多个 keyword/value 对。 每个 query 是一个字符串形式、S 表达式形式或已编译形式的 tree-sitter 查询。
对每个 query,其前面的 keyword/value 对为其附加元信息。
:language 关键字声明 query 的语言。
:feature 关键字设置 query 的功能名称。
用户可以通过 treesit-font-lock-level 和
treesit-font-lock-feature-list(见下文)控制启用哪些功能。
这两个关键字是必需的(个别情况除外)。
其他关键字为可选:
| 关键字 | 取值 | 说明 |
|---|---|---|
:override | nil | 若区域已有外观,则丢弃新外观 |
t | 始终应用新外观 | |
append | 将新外观追加到现有外观之后 | |
prepend | 将新外观插入到现有外观之前 | |
keep | 仅为无外观的区域填充新外观 | |
:default-language | language | 此关键字之后的所有 query 默认使用该语言 |
Lisp 程序在 query 中用捕获名称(以 @ 开头的名称)标记模式,
tree-sitter 会返回带有相同捕获名称标记的匹配节点。
出于高亮目的,query 中的捕获名称应当是外观名,
如 font-lock-keyword-face。被捕获的节点将使用该外观高亮。
捕获名称也可以是函数名。此时该函数会接收 4 个参数:
node、override、start 和 end,
其中 node 是节点本身,override 是捕获该节点的规则的
:override 属性,start 和 end 限定了该函数应当高亮的区域。
(如果该函数希望遵守 override 参数,可以使用 treesit-fontify-with-override。)
除了给出的 4 个参数外,该函数还应接受更多可选参数,以便未来扩展。
如果一个捕获名称既是外观又是函数,外观优先。 如果一个捕获名称既不是外观也不是函数,则会被忽略。
这是一个由功能符号列表组成的列表。列表中的每个元素代表一个装饰级别。
treesit-font-lock-level 控制哪些级别被激活。
列表中的每个元素形如 (feature …),
其中每个 feature 对应 treesit-font-lock-rules 中定义的查询的
:feature 值。从该列表中移除某个功能符号会在字体锁定时禁用对应的查询。
许多编程语言常用的功能名称包括:
definition、type、assignment、builtin、
constant、keyword、string-interpolation、
comment、doc、string、operator、
preprocessor、escape-sequence 和 key。
主模式可自由细分或扩展这些通用功能。
其中部分功能需要说明:
definition 高亮被定义的对象,例如函数定义中的函数名、结构体定义中的结构体名、变量定义中的变量名;
assignment 高亮被赋值的对象,例如赋值语句中的变量或字段;
key 高亮键值对中的键,例如 JSON 对象或 Python 字典中的键;
doc 高亮文档字符串或文档注释。
例如,该变量的值可以是:
((comment string doc) ; level 1 (function-name keyword type builtin constant) ; level 2 (variable-name string-interpolation key)) ; level 3
主模式应在调用 treesit-major-mode-setup 之前设置此变量。
要让该变量生效,Lisp 程序应调用
treesit-font-lock-recompute-features(会相应重置
treesit-font-lock-settings),
或调用 treesit-major-mode-setup(它内部会调用
treesit-font-lock-recompute-features)。
基于 tree-sitter 的字体锁定的设置列表。
每个设置的具体格式被视为内部实现。
应当始终使用 treesit-font-lock-rules 来设置此变量。
多语言主模式应在 treesit-range-functions 中提供范围函数,
Emacs 会在高亮某一区域前相应设置范围(see Parsing Text in Multiple Languages)。
对于编程语言而言,主模式的一个重要功能就是提供自动缩进。
该功能分为两部分:一是确定一行代码的正确缩进量,二是确定何时重新缩进该行。
默认情况下,每当你输入 electric-indent-chars 中的字符时,Emacs 都会重新缩进当前行,
该变量默认只包含换行符。主模式可以根据语言的语法向 electric-indent-chars 添加更多字符。
在 Emacs 中,确定正确缩进量由 indent-line-function 控制(see Indentation Controlled by Major Mode)。
在某些模式下,“正确”的缩进无法被可靠判定,典型情况是缩进本身具有语法意义,
多种缩进都合法但含义不同。这种情况下,该模式应当设置 electric-indent-inhibit,
确保不会违背用户意图反复自动缩进。
编写一个优秀的缩进函数往往比较困难,在很大程度上仍是一门需要经验的技巧。 许多主模式作者会先编写一个能处理简单情况的基础缩进函数, 例如直接参照上一行文本的缩进。对于大多数并非严格基于行的编程语言, 这种方式扩展性很差:想要改进这类函数以支持更多复杂场景,难度会越来越大, 最终会变成一个庞大、复杂、难以维护,以至于没人敢改动的缩进函数。
一个优秀且可维护的缩进函数通常需要根据语言语法真正解析文本。 幸运的是,不必像编译器那样做精细解析;但另一方面,缩进代码中内置的解析器 需要对语法不合法的代码有一定容忍度。
优秀且可维护的缩进函数通常分为两类: 一类是从某个安全起点 向前解析 直到目标位置,另一类是从目标位置 向后解析。 两者并没有绝对优劣:向后解析通常比向前解析更难,因为编程语言本身是按向前解析设计的; 但对缩进需求来说,它的优点是不需要猜测安全起点, 并且通常只分析最少的文本即可确定一行缩进, 因此缩进受前面无关代码中语法错误的影响更小。 而向前解析通常更简单,并且支持一次解析、高效地对整个区域重新缩进。
与其从零编写自己的缩进函数,通常更推荐复用已有实现或依赖通用缩进引擎。 遗憾的是这类引擎并不多。CC-mode 缩进代码(用于 C、C++、Java、Awk 等类似模式) 多年来已经变得更加通用,因此如果你的语言与其中某种语言较为相似, 可以尝试使用该引擎。另一个是 SMIE,它采用类似 Lisp 符号表达式的思路,并适配到非 Lisp 语言。 还有一种方式是依赖完备的解析器,例如 tree-sitter 库。
SMIE 是一个提供通用结构导航与缩进引擎的包。它基于一个使用运算符优先文法的极简解析器, 允许主模式将 Lisp 的符号表达式导航能力扩展到非 Lisp 语言,并提供简单易用且可靠的自动缩进。
与编译器中常见的解析技术相比,运算符优先文法是一种非常基础的解析技术。
它具有以下特点:解析能力非常有限,基本无法检测语法错误,
但算法效率高,并且可以向前或向后双向解析。
在实际应用中,这意味着 SMIE 可以基于向后解析实现缩进,
可以同时提供 forward-sexp 和 backward-sexp 功能,
并且无需额外处理就能自然地在语法不合法的代码上工作。
缺点是,这也意味着大多数编程语言无法直接用 SMIE 正确解析,
至少需要借助一些特殊技巧(see 适配简易解析器)。
SMIE 旨在为代码结构导航和其他依赖代码语法结构的各类功能提供一站式解决方案,
尤其适用于自动缩进。主入口函数是 smie-setup,
通常在主模式初始化时调用。
设置 SMIE 结构导航与缩进功能。
grammar 是由 smie-prec2->grammar 生成的文法表。
rules-function 是一组缩进规则,供 smie-rules-function 使用。
keywords 为附加参数,可包含以下关键字:
:forward-token fun:指定向前词法分析器。
:backward-token fun:指定向后词法分析器。
调用该函数后,forward-sexp、backward-sexp、transpose-sexps
等命令即可正确处理语法表已支持的配对括号之外的结构元素。
例如,如果提供的文法足够精确,transpose-sexps
可以根据语言优先级规则正确交换 + 运算符的两个参数。
调用 smie-setup 也足以让 TAB 缩进按预期工作,
扩展 blink-matching-paren 以支持 begin...end 之类的结构,
并提供一些可绑定到主模式按键映射的命令。
关闭最近打开但尚未闭合的代码块。
功能类似 down-list,但同时会处理括号之外的嵌套标记,如 begin...end。
SMIE 的优先文法为每个标记分配一对优先级:左优先级与右优先级。
若标记 T1 的右优先级小于 T2 的左优先级,我们记为 T1 < T2。
可以把这个 < 理解为一种括号关系:若出现 ... T1 something T2 ...,
则应解析为 ... T1 (something T2 ...,而非 ... T1 something) T2 ...。
若为 T1 > T2,则对应后一种解释。若为 T1 = T2,
表示 T2 与 T1 属于同一语法结构,典型如 "begin" = "end"。
这样的优先级对足以表达中缀运算符的左结合、右结合,
以及括号式嵌套等多种常见情况。
接收一个 prec2 文法表 table,返回可用于 smie-setup 的关联表。
prec2 表本身由下面的函数构建。
接收多个 prec2 表,合并为一个新的 prec2 表。
从优先级表 precs 构建 prec2 表。
precs 应是按优先级排序的列表(例如 "+" 排在 "*" 前面),
元素形如 (assoc op ...),
其中每个 op 是作为运算符的标记;
assoc 为结合性,可为 left、right、assoc 或 nonassoc。
同一元素中的所有运算符共享同一优先级与结合性。
允许使用 BNF 表示法定义文法。 它接收文法的 bnf 描述以及冲突消解规则 resolvers,返回一个 prec2 表。
bnf 是非终结符定义列表,形如 (nonterm rhs1 rhs2 ...),
每个 rhs 是由终结符(标记)或非终结符组成的非空列表。
并非所有文法都被接受:
此外可能出现冲突:
"else" 这类内部标记)。
优先级冲突可以通过 resolvers 来解决,它是一个 优先级(precs) 表的列表(参见 smie-precs->prec2):对每一个优先级冲突,如果这些 precs 表中指定了某个特定约束,就使用该约束来解决冲突;否则会报告冲突,并任意选择其中一个冲突约束生效,其余约束则直接忽略。
为语言定义 SMIE 语法的常规方式是, 通过给出一组 BNF 规则定义一个存储优先级表的全新全局变量。 例如,一门类 Pascal 小型语言的语法定义可如下所示:
(require 'smie) (defvar sample-smie-grammar (smie-prec2->grammar (smie-bnf->prec2
'((id)
(inst ("begin" insts "end")
("if" exp "then" inst "else" inst)
(id ":=" exp)
(exp))
(insts (insts ";" insts) (inst))
(exp (exp "+" exp)
(exp "*" exp)
("(" exps ")"))
(exps (exps "," exps) (exp)))
'((assoc ";"))
'((assoc ","))
'((assoc "+") (assoc "*")))))
有几点需要注意:
begin ... end 框架)
出现在任意位置。
id 没有右侧规则:这并不意味着它仅能匹配空串,
因为前文已提到任意 S 表达式序列均可出现在任意位置。
";" 视为语句 分隔符,
SMIE 对此能很好地处理。
"," 和 ";")
最好通过 (foo (foo "separator" foo) ...) 这类 BNF 规则定义,
这类规则会产生优先级冲突,随后通过显式指定 (assoc "separator") 解决冲突。
("(" exps ")") 规则并非用于配对括号,
因为 SMIE 会自动配对语法表中标记为括号语法的任意字符。
该规则(配合 exps 的定义)实际作用是明确 "," 不应出现在括号之外。
left 或 right,
通常更适合用 assoc 将运算符标记为可结合的。
因此上述代码中 "+" 和 "*" 均定义为 assoc,
尽管该语言在形式上定义其为左结合。
SMIE 内置一个预定义的词法分析器,它按如下方式使用语法表:
任意具有单词或符号语法的字符序列会被视为一个标记,
任意具有标点符号语法的字符序列同样如此。
这个默认词法分析器通常是不错的起点,
但对任意特定语言而言很少能完全适用。
例如,它会将 "2,+3" 拆分为 3 个标记:"2"、",+" 和 "3"。
若要向 SMIE 描述你所用语言的词法规则,需要两个函数: 一个用于获取下一个标记,另一个用于获取上一个标记。 这些函数通常会先跳过空白符与注释, 再查看下一段文本是否为特殊标记。 若是,则应跳过该标记并返回其描述。 通常直接返回从缓冲区提取的字符串即可, 但也可返回任意自定义内容。示例如下:
(defvar sample-keywords-regexp
(regexp-opt '("+" "*" "," ";" ">" ">=" "<" "<=" ":=" "=")))
(defun sample-smie-forward-token ()
(forward-comment (point-max))
(cond
((looking-at sample-keywords-regexp)
(goto-char (match-end 0))
(match-string-no-properties 0))
(t (buffer-substring-no-properties
(point)
(progn (skip-syntax-forward "w_")
(point))))))
(defun sample-smie-backward-token ()
(forward-comment (- (point)))
(cond
((looking-back sample-keywords-regexp (- (point) 2) t)
(goto-char (match-beginning 0))
(match-string-no-properties 0))
(t (buffer-substring-no-properties
(point)
(progn (skip-syntax-backward "w_")
(point))))))
注意这些词法分析器在遇到括号时会返回空串。
原因是 SMIE 会自动处理语法表中定义的括号。
更具体地说,若词法分析器返回 nil 或空串,
SMIE 会依据语法表将对应文本当作 S 表达式处理。
SMIE 采用的解析技术不允许标记在不同语境下表现出不同行为。 对多数编程语言而言,这会在转换 BNF 语法时产生优先级冲突。
有时,可通过略微调整语法写法规避这类冲突。 例如,对 Modula-2 而言,直观的 BNF 语法可能如下:
...
(inst ("IF" exp "THEN" insts "ELSE" insts "END")
("CASE" exp "OF" cases "END")
...)
(cases (cases "|" cases)
(caselabel ":" insts)
("ELSE" insts))
...
但这会为 "ELSE" 带来冲突:
一方面,IF 规则隐含(诸多关系中)"ELSE" = "END";
另一方面,由于 "ELSE" 出现在 cases 内部,
而 cases 位于 "END" 左侧,因此又有 "ELSE" > "END"。
可通过以下方式解决该冲突:
...
(inst ("IF" exp "THEN" insts "ELSE" insts "END")
("CASE" exp "OF" cases "END")
("CASE" exp "OF" cases "ELSE" insts "END")
...)
(cases (cases "|" cases) (caselabel ":" insts))
...
或
...
(inst ("IF" exp "THEN" else "END")
("CASE" exp "OF" cases "END")
...)
(else (insts "ELSE" insts))
(cases (cases "|" cases) (caselabel ":" insts) (else))
...
不过,调整语法以解决冲突也存在弊端, 因为 SMIE 假定语法反映代码的逻辑结构, 因此更推荐让 BNF 尽量贴近预期的抽象语法树。
另一些情况下,经仔细分析后你可能判定这类冲突并不严重,
直接通过 smie-bnf->prec2 的 resolvers 参数解决即可。
这通常是因为语法本身存在歧义:冲突不影响语法描述的程序集合,
仅影响程序的解析方式。
分隔符与可结合中缀运算符便属于典型场景,
此时可添加类似 '((assoc "|")) 的解析规则。
另一个典型场景是经典的 悬垂 else 问题,
可使用 '((assoc "else" "then")) 解决。
冲突真实存在且无法真正解决、但在实际使用中几乎不会引发问题时,也可采用此方式。
最后,很多时候即便尽力重构语法,仍会残留部分冲突。
不必气馁:解析器无法变得更智能,但你可以让词法分析器尽可能灵活。
因此解决方案是:找到冲突涉及的标记,
将其中一个拆分为两个(或更多)不同标记。
例如,若语法需要区分 "begin" 的两种不兼容用法,
可让词法分析器根据识别到的 "begin" 类型返回不同标记(如 "begin-fun" 和 "begin-plain")。
这会将区分不同场景的工作转移给词法分析器,
使其需要根据上下文文本寻找特定线索完成判断。
基于提供的语法,SMIE 无需额外配置即可实现自动缩进。 但在实际使用中,这种默认缩进风格往往不够理想, 你通常需要在多种场景下对其进行微调。
SMIE 缩进的设计理念是:缩进规则应尽可能**局部化**。 为此,它引入了 虚拟缩进 的概念, 即某一程序位置若位于行首时应具有的缩进量。 当然,如果该位置确实在行首,其虚拟缩进就是当前缩进值; 否则 SMIE 会通过缩进算法计算该位置的虚拟缩进。
在实际使用中,某程序点的虚拟缩进不必与在其前插入换行后的缩进完全一致。
举个例子,C 语言中 { 之后的 SMIE 缩进规则并不关心该 { 是单独占一行,还是位于上一行末尾。
这些不同情况会由 { 之前的缩进规则统一处理。
另一个重要概念是 父节点(parent):
一个标记的 父节点,是包裹它的最近语法结构的起始标记。
例如,else 的父节点是其所属的 if,
而 if 的父节点则是外层语法结构的起始标记。
命令 backward-sexp 可从一个标记跳转到其父节点,但有几点注意事项:
对于 起始标记(openers) (开启一个结构的标记,如 if),
需要将光标置于标记之前;
对其他标记则需将光标置于标记之后。
若父节点是当前标记的 起始标记(opener),backward-sexp 会将光标停在父节点之前,
否则停在父节点之后。
SMIE 缩进规则通过一个函数指定,该函数接收两个参数 method 和 arg,其中 arg 的含义与函数返回值由 method 决定。
method 可取以下值:
:after:此时 arg 为一个标记,函数应返回在 arg 之后进行缩进所用的偏移量 offset。
:before:此时 arg 为一个标记,函数应返回缩进 arg 自身所用的偏移量 offset。
:elem:函数应返回缩进函数参数所用的偏移量(若 arg 为符号 arg),
或基础缩进步长(若 arg 为符号 basic)。
:list-intro:此时 arg 为一个标记,若该标记后跟随一组表达式列表(无分隔符)而非单个表达式,
函数应返回非 nil。
当 arg 为标记时,函数被调用时光标位于该标记之前。
返回值为 nil 始终表示回退到默认行为,
因此函数对不处理的参数应返回 nil。
offset 可取以下值:
nil:使用默认缩进规则。
(column . column):缩进至指定列 column。
:after 而言基准是当前标记,对 :before 而言基准是其父节点。
SMIE 提供一系列专为缩进规则函数设计的辅助函数
(其中部分在其他上下文使用会出错)。
这些函数均以 smie-rule- 为前缀。
若当前标记是所在行的第一个标记,返回非 nil。
若当前标记为 悬挂标记(hanging),返回非 nil。
一个标记是 悬挂(hanging) 的,当且仅当它是行尾标记且前面有其他标记;
单独一行的标记不属于悬挂标记。
若下一个标记在 tokens 列表中,返回非 nil。
若上一个标记在 tokens 列表中,返回非 nil。
若当前标记的父节点在 parents 列表中,返回非 nil。
若当前标记的父节点实际是兄弟节点,返回非 nil。
典型例子是 "," 的父节点恰好是前一个 ","。
返回使当前标记与父节点对齐的合适偏移量。
若 offset 非 nil,则为额外增加的整数偏移。
将当前标记按 分隔符(separator) 进行缩进。
此处所说的 分隔符(separator),指仅用于在某个外层语法结构中分隔多个元素, 自身无实际语义的标记(即通常不会作为抽象语法树的节点存在)。
这类标记一般具有可结合语法,并与其语法父节点紧密关联。
典型例子包括参数列表中的 ","(包裹在括号内),
或语句序列中的 ";"(包裹在 {...} 或 begin...end 框架内)。
method 应为传入 smie-rules-function 的方法名。
以下是一个缩进函数示例:
(defun sample-smie-rules (kind token)
(pcase (cons kind token)
(`(:elem . basic) sample-indent-basic)
(`(,_ . ",") (smie-rule-separator kind))
(`(:after . ":=") sample-indent-basic)
(`(:before . ,(or `"begin" `"(" `"{"))
(if (smie-rule-hanging-p) (smie-rule-parent)))
(`(:before . "if")
(and (not (smie-rule-bolp)) (smie-rule-prev-p "else")
(smie-rule-parent)))))
有几点需要说明:
sample-indent-basic 为 nil,SMIE 将使用全局设置 smie-indent-basic。
主模式也可以缓冲区局部变量的方式设置 smie-indent-basic,但不推荐这样做。
"," 的规则让 SMIE 在逗号位于行首时更智能地处理:
它会适当减少分隔符的缩进,使逗号后的代码对齐,例如:
x = longfunctionname (
arg1
, arg2
);
":=" 之后的缩进规则是必要的,
否则 SMIE 会将 ":=" 视为中缀运算符,
并将右操作数与左操作数对齐。
"begin" 之前的缩进规则是使用虚拟缩进的典型示例:
该规则仅在 "begin" 处于悬挂状态时生效,
即 "begin" 不在行首的情况。
因此它不用于缩进 "begin" 本身,
只用于缩进相对于该 "begin" 的后续内容。
具体来说,该规则会将缩进效果从:
if x > 0 then begin
dosomething(x);
end
改为:
if x > 0 then begin
dosomething(x);
end
"if" 之前的缩进规则与 "begin" 类似,
目的是将 "else if" 视为一个整体,
使一系列条件判断对齐,而非逐个向右缩进。
该函数仅在 "if" 不单独成行时生效,因此使用了 smie-rule-bolp 判断。
如果我们确定 "else" 始终与其 "if" 对齐且总位于行首,
可以使用更高效的规则:
((equal token "if")
(and (not (smie-rule-bolp))
(smie-rule-prev-p "else")
(save-excursion
(sample-smie-backward-token)
(cons 'column (current-column)))))
这种写法的优点是直接复用前一个 "else" 的缩进,
而不必回溯到整个判断序列的第一个 "if"。
如果你使用的主模式由 SMIE 提供缩进支持,
可以按个人习惯自定义缩进。
你可以按模式配置(使用选项 smie-config),
或按文件配置(在文件局部变量中使用函数 smie-config-local)。
该选项允许按模式自定义缩进,
是一个元素格式为 (mode . rules) 的关联列表。
规则的具体格式参见变量文档;
但使用命令 smie-config-guess 通常更简便。
该命令会自动推算出适合你偏好风格的缩进设置。 只需打开一个已按你的风格缩进好的文件并执行该命令即可。
在使用 smie-config-guess 后执行此命令,
可将设置保存以便后续会话使用。
该命令显示用于缩进当前行的规则。
该命令添加一条局部规则以调整当前行的缩进。
该函数为当前缓冲区添加缩进规则 rules。
这些规则会追加到 smie-config 中定义的模式专属规则之后。
如需为特定文件指定自定义缩进规则,
可在文件局部变量中添加如下形式的配置:
eval: (smie-config-local '(rules))。
This command adds a local rule to adjust the indentation of the current line.
当 Emacs 基于 tree-sitter 库编译时(see Parsing Program Source), 能够解析程序源代码并生成语法树。 该语法树可用于指导程序源码的缩进命令。 为获得最大灵活性,可以为每种语言编写自定义缩进函数, 查询语法树并完成缩进,但这工作量较大。 更简便的方式是使用下文介绍的简易缩进引擎: 主模式只需编写若干缩进规则,其余工作由引擎完成。
要启用基于解析器的缩进引擎,
需设置 treesit-simple-indent-rules 或 treesit-indent-function,
然后调用 treesit-major-mode-setup。
(treesit-major-mode-setup 的作用就是将 indent-line-function
设为 treesit-indent,并将 indent-region-function 设为 treesit-indent-region。)
该变量存储 treesit-indent 实际调用的函数。
默认值为 treesit-simple-indent。
未来可能会加入其他更复杂的缩进引擎。
该局部变量存储每种语言的缩进规则。它是一个关联列表,元素格式为 (language . rules),其中 language 为语言符号,rules 为格式为 (matcher anchor offset) 的元素列表。
首先,Emacs 将当前行开头最小的 tree-sitter 节点传递给 matcher;若其返回非 nil,则该规则生效。随后 Emacs 将该节点传递给 anchor,由其返回一个缓冲区位置。Emacs 取该位置的列号,加上 offset,结果即为当前行的缩进列数。
matcher 与 anchor 均为函数,Emacs 为其提供了便捷的默认实现。
每个 matcher 或 anchor 均为接收三个参数的函数:node、parent 与 bol。参数 bol 为需要缩进的缓冲区位置,即行首之后首个非空白字符的位置。参数 node 为起始于该位置的最大节点(非根节点);parent 为 node 的父节点。但若该位置处于空白区域或多行字符串内部,则无节点起始于此,此时 node 为 nil,parent 则为覆盖该位置的最小节点。
matcher 在规则生效时应返回非 nil,anchor 则应返回一个缓冲区位置。
offset 可以是整数、值为整数的变量,或返回整数的函数。若为函数,则与匹配器、定位器一样,接收 node、parent 与 bol 三个参数。
该变量为 treesit-simple-indent-rules 中 matcher 与 anchor 的默认函数列表。每个预设均代表一个接收三个参数的函数:node、parent 与 bol。可用的默认函数如下:
no-node ¶该匹配器函数接收三个参数:node、parent 与 bol。当 node 为 nil(即无节点起始于 bol)时返回非 nil,表示匹配成功。该情况常见于 bol 位于空行或多行字符串内部等场景。
parent-is ¶该匹配器接收一个参数 type,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,当 parent 的类型匹配正则表达式 type 时返回非 nil。
node-is ¶该匹配器接收一个参数 type,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,当 node 的类型匹配正则表达式 type 时返回非 nil。
field-is ¶该匹配器接收一个参数 name,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,当 node 在 parent 中的字段名匹配正则表达式 name 时返回非 nil。
query ¶该匹配器接收一个参数 query,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,当使用 query 查询 parent 能够捕获 node 时返回非 nil(see Pattern Matching Tree-sitter Nodes)。
match ¶该匹配器接收五个参数:node-type、parent-type、node-field、node-index-min 与 node-index-max,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,并在以下条件均满足时返回非 nil:node 类型匹配 node-type、parent 类型匹配 parent-type、node 在 parent 中的字段名匹配 node-field,且 node 在兄弟节点中的索引介于 node-index-min 与 node-index-max 之间。若某参数为 nil,则跳过该项检查。例如,匹配父节点为 argument_list 的首个子节点可使用:
(match nil "argument_list" nil 0 0)
此外,node-type 可使用特殊值 null,用于匹配 node 为 nil 的情况。
n-p-gp ¶为“节点-父节点-祖父节点”的缩写,该匹配器接收三个参数:node-type、parent-type 与 grandparent-type,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,并在以下条件均满足时返回非 nil:(1) node-type 匹配 node 类型;(2) parent-type 匹配 parent 类型;(3) grandparent-type 匹配 parent 的父节点类型。若任一类型参数为 nil,则跳过该项检查。
comment-end ¶该匹配器函数接收三个参数:node、parent 与 bol,当光标位于注释结束标记之前时返回非 nil。注释结束标记由正则表达式 comment-end-skip 定义。
catch-all ¶该匹配器函数接收三个参数:node、parent 与 bol,始终返回非 nil,表示匹配成功。
first-sibling ¶该定位器函数接收三个参数:node、parent 与 bol,返回 parent 首个子节点的起始位置。
nth-sibling ¶该定位器接收两个参数:n 与可选参数 named,返回一个函数;该返回函数接收 node、parent 与 bol 三个参数,返回 parent 的第 n 个子节点的起始位置。若 named 非 nil,则仅统计具名子节点(see named node)。
parent ¶该定位器函数接收三个参数:node、parent 与 bol,返回 parent 的起始位置。
grand-parent ¶该定位器函数接收三个参数:node、parent 与 bol,返回 parent 的父节点起始位置。
great-grand-parent ¶该定位器函数接收三个参数:node、parent 与 bol,返回 parent 的父节点的父节点起始位置。
parent-bol ¶该定位器函数接收三个参数:node、parent 与 bol,返回 parent 起始所在行的首个非空白字符位置。
standalone-parent ¶该定位器函数接收三个参数:node、parent 与 bol。它查找 node 首个独占一行的祖先节点(父、祖父等),并返回该节点的起始位置。“独占一行”指节点起始所在行中,节点之前仅有空白字符。
prev-sibling ¶该定位器函数接收三个参数:node、parent 与 bol,返回 node 前一个兄弟节点的起始位置。
no-indent ¶该定位器函数接收三个参数:node、parent 与 bol,返回 node 的起始位置。
prev-line ¶该定位器函数接收三个参数:node、parent 与 bol,返回上一行的首个非空白字符位置。
column-0 ¶该定位器函数接收三个参数:node、parent 与 bol,返回当前行首(第 0 列)位置。
comment-start ¶该定位器函数接收三个参数:node、parent 与 bol,返回注释起始标记之后的位置。注释起始标记由正则表达式 comment-start-skip 定义。该函数假定 parent 为注释节点。
prev-adaptive-prefix ¶该定位器函数接收三个参数:node、parent 与 bol。它尝试将 adaptive-fill-regexp 与上一个非空行开头的文本匹配。若匹配成功,则返回匹配结束位置,否则返回 nil。但若当前行以某种前缀(如 ‘-’)开头,则返回上一行前缀的起始位置,使两行前缀对齐。该定位器适用于实现块注释类 indent-relative 的缩进行为。
以下为若干可辅助编写基于解析器缩进规则的工具函数。
该命令按照主模式 mode 检查当前缓冲区的缩进。它会依据 mode 对缓冲区进行缩进,并与当前缩进结果对比,随后弹出缓冲区展示差异。正确缩进(目标值)以绿色显示,当前缩进以红色显示。
编写缩进规则时,使用 treesit-inspect-mode 同样很有帮助(see Tree-sitter Language Grammar)。
Desktop Save Mode 用于在不同会话间保存 Emacs 的状态。使用该模式的用户级命令已在《GNU Emacs 手册》中说明(see Saving Emacs Sessions in the GNU Emacs Manual)。缓冲区关联文件的模式无需额外配置即可使用该功能。
若要使未关联文件的缓冲区也保存状态,其主模式需将缓冲区局部变量 desktop-save-buffer 绑定为非 nil 值。
若该缓冲区局部变量非 nil,则在桌面保存时会将缓冲区状态写入桌面文件。若其值为函数,则在桌面保存时以 desktop-dirname 为参数调用该函数,并将返回值与对应缓冲区状态一同保存至桌面文件。当辅助信息中包含文件名时,应通过如下调用格式化:
(desktop-file-name file-name desktop-dirname)
若要恢复未关联文件的缓冲区,主模式需定义对应的恢复函数,并将该函数加入关联列表 desktop-buffer-mode-handlers。
元素格式如下的关联列表:
(major-mode . restore-buffer-function)
函数 restore-buffer-function 将以如下参数列表调用:
(buffer-file-name buffer-name desktop-buffer-misc)
并返回恢复后的缓冲区。其中 desktop-buffer-misc 为可选绑定至 desktop-save-buffer 的函数所返回的值。
GNU Emacs 内置了便捷的帮助功能,其中绝大部分功能的信息都来源于与函数和变量相关联的文档字符串。本章将介绍如何在 Lisp 程序中访问这些文档字符串。
文档字符串的内容需要遵循特定的规范。具体来说,其第一行应当是一个完整的句子(或两个完整的句子),简要描述该函数或变量的功能。关于如何编写优质的文档字符串,see Tips for Documentation Strings。
需要注意的是,Emacs 的文档字符串与 Emacs 手册并非同一概念。手册拥有独立的源文件,采用 Texinfo 语言编写;而文档字符串则直接定义在其所对应的函数和变量的定义体中。仅靠一组文档字符串无法构成一份完整的手册,因为优质的手册不会以这种方式组织内容,而是围绕讨论的主题来编排。
有关用于显示文档字符串的命令,可参见 Help in The GNU Emacs Manual。
文档字符串采用 Lisp 的字符串语法编写,即文本内容被双引号包裹。实际上,它就是一个真实的 Lisp 字符串。当该字符串出现在函数或变量定义中对应的位置时,就会作为该函数或变量的文档说明。
在函数定义(lambda 或 defun 形式)中,文档字符串指定在参数列表之后,并且通常直接存储在函数对象中。See 函数的文档字符串。你也可以将函数文档存储在函数名的 function-documentation 属性中(see 访问文档字符串)。
在变量定义(defvar 形式)中,文档字符串指定在初始值之后。See 定义全局变量。该字符串会存储在变量的 variable-documentation 属性中。
在某些情况下,Emacs 不会将文档字符串常驻内存。主要有两种情形:其一,为节省内存,原语函数(see 什么是函数?)和内置变量的文档会存储在名为 DOC 的文件中,该文件所在目录由 doc-directory 指定(see 访问文档字符串);其二,当函数或变量从字节编译文件加载时,Emacs 会避免加载其文档字符串(see 文档字符串与编译)。在这两种情况下,Emacs 仅在需要时(例如用户为某个函数调用 C-h f(describe-function)命令时)才会从文件中查找对应的文档字符串。
文档字符串中可以包含特殊的 按键替换序列(key substitution sequences),这类序列引用的按键绑定仅在用户查看文档时才会被解析。这一机制确保即便用户修改了默认的按键绑定,帮助命令仍能显示正确的按键。See 文档中的按键绑定替换。
在自动加载命令的文档字符串中(see 自动加载),这些按键替换序列还有一个额外的特殊作用:当用户对该命令执行 C-h f 操作时,会触发自动加载机制。(这一机制是为了在 *Help* 框架中正确建立超链接。)
该函数返回记录在 symbol 属性列表中、对应 property 属性下的文档字符串。它最常用于查找变量的文档字符串,此时 property 为 variable-documentation。此外,它也可用于查找其他类型的文档,例如自定义组的文档(但函数文档请使用下文的 documentation 函数)。
若属性值指向存储在 DOC 文件或字节编译文件中的文档字符串,该函数会查找并返回该字符串。
若属性值不为 nil、不是字符串,且不指向文件中的文本,则会将其作为 Lisp 表达式求值以得到字符串。
最后,该函数会通过 substitute-command-keys 处理字符串,替换其中的按键绑定(see 文档中的按键绑定替换)。若 verbatim 非 nil,则跳过此步骤。
(documentation-property 'command-line-processed
'variable-documentation)
⇒ "Non-nil once command line has been processed"
(symbol-plist 'command-line-processed)
⇒ (variable-documentation 188902)
(documentation-property 'emacs 'group-documentation)
⇒ "Customization of the One True Editor."
该函数返回 function 的文档字符串。它支持普通函数、宏、命名键盘宏以及特殊形式。
若 function 为符号,该函数会先查找该符号的 function-documentation 属性;若该属性值非 nil,则文档取自该值(若值不是字符串,则对其求值)。
若 function 不是符号,或没有 function-documentation 属性,则 documentation 会从实际的函数定义中提取文档字符串,必要时从文件中读取。
最后,除非 verbatim 非 nil,否则该函数会调用 substitute-command-keys。处理结果即为要返回的文档字符串。
若 function 无函数定义,documentation 会触发 void-function 错误。但函数定义没有文档字符串是允许的,此时 documentation 返回 nil。
documentation 使用的泛化函数,用于从函数对象中提取原始文档字符串。你可以为特定类型的函数添加对应的方法,以指定其文档字符串的获取方式。
该函数以面孔的形式返回 face 的文档字符串。
下面是一个使用 documentation 与 documentation-property 两个函数,在 *Help* 框架中显示多个符号文档字符串的示例。
(defun describe-symbols (pattern)
"Describe the Emacs Lisp symbols matching PATTERN.
All symbols that have PATTERN in their name are described
in the *Help* buffer."
(interactive "sDescribe symbols matching: ")
(let ((describe-func
(lambda (s)
;; Print description of symbol. (if (fboundp s) ; It is a function. (princ (format "%s\t%s\n%s\n\n" s (if (commandp s) (let ((keys (where-is-internal s))) (if keys (concat "Keys: " (mapconcat 'key-description keys " ")) "Keys: none")) "Function")
(or (documentation s)
"not documented"))))
(if (boundp s) ; It is a variable.
(princ
(format "%s\t%s\n%s\n\n" s
(if (custom-variable-p s)
"Option " "Variable")
(or (documentation-property
s 'variable-documentation)
"not documented"))))))
sym-list)
;; Build a list of symbols that match pattern.
(mapatoms (lambda (sym)
(if (string-match pattern (symbol-name sym))
(setq sym-list (cons sym sym-list)))))
;; Display the data.
(help-setup-xref (list 'describe-symbols pattern)
(called-interactively-p 'interactive))
(with-help-window (help-buffer)
(mapcar describe-func (sort sym-list)))))
describe-symbols 函数的功能与 apropos 类似,但提供的信息更详细。
(describe-symbols "goal") ---------- Buffer: *Help* ---------- goal-column Option Semipermanent goal column for vertical motion, as set by ...
minibuffer-temporary-goal-position Variable not documented
set-goal-column Keys: C-x C-n Set the current horizontal position as a goal for C-n and C-p.
Those commands will move to this position in the line moved to rather than trying to keep the same horizontal position. With a non-nil argument ARG, clears out the goal column so that C-n and C-p resume vertical motion. The goal column is stored in the variable ‘goal-column’. (fn ARG)
temporary-goal-column Variable Current goal column for vertical motion. It is the column where point was at the start of the current run of vertical motion commands. When moving by visual lines via the function ‘line-move-visual’, it is a cons cell (COL . HSCROLL), where COL is the x-position, in pixels, divided by the default column width, and HSCROLL is the number of columns by which window is scrolled from left margin. When the ‘track-eol’ feature is doing its job, the value is ‘most-positive-fixnum’. ---------- Buffer: *Help* ----------
该函数用于构建 Emacs 的过程中,即在可执行 Emacs 转储之前。它会查找存储在文件 filename 中的文档字符串位置,并将这些位置记录到函数定义与变量属性列表的内存中。See Building Emacs。
Emacs 从 emacs/etc 目录读取文件 filename。当转储后的 Emacs 后续运行时,会在 doc-directory 目录下查找同一文件。通常 filename 为 "DOC"。
该变量保存目录名称,该目录应包含文件 "DOC",其中存储了内置函数与变量的文档字符串。
多数情况下,该目录与 data-directory 相同。若你从构建目录直接运行 Emacs 而未执行安装,则二者可能不同。See Definition of data-directory。
当文档字符串引用按键序列时,应使用当前实际生效的按键绑定。可以通过下文描述的若干特殊文本序列实现这一点。以常规方式访问文档字符串时,会将这些特殊序列替换为当前的按键绑定信息,这一过程通过调用 substitute-command-keys 完成。你也可以直接调用该函数。
以下是特殊序列及其含义的列表:
\[command]表示可调用 command 的按键序列;若该命令无绑定按键,则显示为 ‘M-x command’。
\{mapvar}表示变量 mapvar 的值所对应的按键映射概览。该概览由 describe-bindings 生成。
概览通常不包含菜单绑定,但若 substitute-command-keys 的 include-menus 参数非 nil,则会包含菜单绑定。
\<mapvar>本身不输出任何文本,仅产生副作用:将本文档字符串中后续所有 ‘\[command]’ 序列所使用的按键映射指定为 mapvar 的值。
\`KEYSEQ'表示按键序列 KEYSEQ,显示面孔与命令替换结果一致。该序列仅应在按键序列无对应命令时使用,例如通过 read-key-sequence 直接读取的按键。其必须是符合 key-valid-p 的合法按键序列。也可用于命令名,如 ‘\`M-x foo'’,使其以按键序列样式高亮,但不执行 ‘\[foo]’ 那样的按键翻译。
`(反引号)表示左引号。
根据 text-quoting-style 的值,会生成左单引号、撇号或反引号。
See 文本引用样式。
'(撇号)表示右引号。
根据 text-quoting-style 的值,会生成右单引号或撇号。
\=对其后字符进行转义并自身被忽略;因此 ‘\=`’ 输出 ‘`’,‘\=\[’ 输出 ‘\[’,‘\=\=’ 输出 ‘\=’。
\+表示紧随其后的符号在 *Help* 框架中不应标记为链接。
请注意:在 Emacs Lisp 字符串中书写时,每个 ‘\’ 都必须写成两个(see 字符串语法)。
该函数扫描 string 中的上述特殊序列并将其替换为对应内容,以字符串形式返回结果。这使得文档可以准确显示用户自定义后的按键绑定。默认情况下,按键绑定会使用特殊面孔 help-key-binding;若可选参数 no-face 非 nil,则不会为结果字符串添加该面孔。
若一个命令有多个绑定,该函数通常使用找到的第一个。你可以为命令指定 :advertised-binding 符号属性来指定优先显示的绑定,示例如下:
(put 'undo :advertised-binding [?\C-/])
:advertised-binding 属性也会影响菜单项中显示的绑定(see 菜单栏)。若该属性指定的按键并非该命令实际拥有的绑定,则会被忽略。
以下是特殊序列的使用示例:
(substitute-command-keys "To abort recursive edit, type `\\[abort-recursive-edit]'.") ⇒ "To abort recursive edit, type ‘C-]’."
(substitute-command-keys
"The keys that are defined for the minibuffer here are:
\\{minibuffer-local-must-match-map}")
⇒ "The keys that are defined for the minibuffer here are:
? minibuffer-completion-help
SPC minibuffer-complete-word
TAB minibuffer-complete
C-j minibuffer-complete-and-exit
RET minibuffer-complete-and-exit
C-g abort-recursive-edit
"
按键映射描述通常不包含菜单项,但若 include-menus 非 nil,则会包含。
(substitute-command-keys "To abort a recursive edit from the minibuffer, type \ `\\<minibuffer-local-must-match-map>\\[abort-recursive-edit]'.") ⇒ "To abort a recursive edit from the minibuffer, type ‘C-g’."
该函数行为与 substitute-command-keys 类似,但仅替换引号字符。
文档字符串中的文本还有其他特殊约定—例如可以引用本手册中的函数、变量与章节。详情参见 See Tips for Documentation Strings。
通常,反引号和撇号在文档字符串与诊断信息中会被特殊处理,转换为成对的单引号(也称 “弯引号”)。例如,文档字符串 "Alias for `foo'." 与函数调用 (message "Alias for `foo'.") 都会转换为 "Alias for ‘foo’."。较少见的情况下,Emacs 会原样显示反引号与撇号,或仅显示为撇号(如 "Alias for 'foo'.")。
文档字符串与消息格式应保证在任意样式下均可正常显示。例如,文档字符串 "Alias for 'foo'." 通常不符合预期,因为它可能显示为 "Alias for ’foo’.",这在英文中并非标准写法。
有时无论文本引用样式如何,你都需要原样显示反引号或撇号而不被转换。在文档字符串中可通过转义实现。例如,文档字符串 "\\=`(a ,(sin 0)) ==> (a 0.0)" 中的反引号用于表示 Lisp 代码,因此被转义,无论引用样式如何都会原样显示。在调用 message 或 error 时,可通过 "%s" 格式搭配 format 调用避免转换。例如,(message "%s" (format "`(a ,(sin %S)) ==> (a %S)" x (sin x))) 会始终以反引号开头显示消息。
该用户选项的值为一个符号,指定 Emacs 在帮助与消息文本中使用的单引号样式。若值为 curve,则使用弯引号,样式为 ‘like this’;若为 straight,则使用直撇号,样式为 'like this';若为 grave,则不转换引号,保持 `like this',即 Emacs 25 版本之前的标准样式。默认值 nil 在可显示弯引号时等效于 curve,否则等效于 grave。
该选项在弯引号显示异常的平台上很有用。你可以根据个人习惯自由自定义。
不应直接读取变量 text-quoting-style 的值。而应使用同名函数,在上述 nil 情况下动态计算当前终端适用的正确引用样式。
下列函数将事件、按键序列或字符转换为文本描述。这些描述适用于在消息中包含任意文本字符或按键序列,因为它们会将非打印字符与空白字符转换为可打印字符序列。非空白的可打印字符的描述即为字符本身。
该函数返回一个字符串,以 Emacs 标准记法表示 sequence 中的输入事件。若 prefix 非 nil,则为引导至 sequence 的输入事件序列,并包含在返回值中。两个参数均可为字符串、向量或列表。有关合法事件的更多信息参见 See 输入事件。
(key-description [?\M-3 delete])
⇒ "M-3 <delete>"
(key-description [delete] "\M-3")
⇒ "M-3 <delete>"
另见下文 single-key-description 的示例。
该函数以 Emacs 键盘输入标准记法返回描述 event 的字符串。普通可打印字符原样显示;控制字符以 ‘C-’ 开头;元字符以 ‘M-’ 开头;空格、制表符等显示为 ‘SPC’、‘TAB’ 等。功能键符号放在尖括号 ‘<…>’ 中。列表形式的事件以列表 CAR 位置的符号名表示,并放在尖括号内。
若可选参数 no-angles 非 nil,则省略功能键与事件符号外的尖括号,用于兼容不使用该括号的旧版 Emacs。
(single-key-description ?\C-x)
⇒ "C-x"
(key-description "\C-x \M-y \n \t \r \f123")
⇒ "C-x SPC M-y SPC C-j SPC TAB SPC RET SPC C-l 1 2 3"
(single-key-description 'delete)
⇒ "<delete>"
(single-key-description 'C-mouse-1)
⇒ "C-<mouse-1>"
(single-key-description 'C-mouse-1 t)
⇒ "C-mouse-1"
该函数以 Emacs 文本字符标准记法返回描述 character 的字符串,用法与 single-key-description 类似,但参数必须是通过 characterp 检测的合法字符编码(see Character Codes)。该函数对控制字符的描述以脱字符开头(Emacs 在框架中通常以此显示控制字符)。带修饰位的字符会导致该函数抛出错误(带 Control 修饰的 ASCII 字符除外,会按控制字符表示)。
(text-char-description ?\C-c)
⇒ "^C"
(text-char-description ?\M-m)
error→ Wrong type argument: characterp, 134217837
该函数主要用于处理键盘宏,但也可大致作为 key-description 的逆操作。传入由空格分隔的按键描述字符串,返回包含对应事件的字符串或向量。(是否为合法按键序列取决于所用事件,参见 See 按键序列。)若 need-vector 非 nil,返回值始终为向量。
Emacs 提供多种内置帮助函数,用户均可通过前缀键 C-h 的子命令访问。更多信息参见 Help in The GNU Emacs Manual。本节介绍用于访问相同信息的程序级接口。
该函数查找所有名称包含 apropos 模式 pattern 匹配内容的有效符号。apropos 模式可以是待匹配单词、至少匹配两个单词的空格分隔列表,或正则表达式(若出现正则表达式特殊字符)。符号为有效符号,当且仅当其具有函数、变量或面孔定义,或拥有属性。
函数返回元素格式如下的列表:
(symbol score function-doc variable-doc plist-doc widget-doc face-doc group-doc)
其中 score 为整数,表示该符号匹配的相关程度。其余各项分别为 symbol 作为函数、变量等的文档字符串或 nil。
该函数同时在名为 *Apropos* 的框架中显示符号,并从文档字符串开头提取一行作为简介。
若 do-all 非 nil,或用户选项 apropos-do-all 非 nil,则 apropos 还会显示找到函数的按键绑定,并显示**所有**已 intern 的符号而非仅有效符号(同时也会在返回值中列出)。
该变量的值为帮助键 C-h 后续字符所使用的局部按键映射。
该符号并非函数,其函数定义单元中保存名为 help-map 的按键映射。它在 help.el 中定义如下:
(keymap-set global-map (key-description (string help-char)) 'help-command) (fset 'help-command help-map)
该变量的值为帮助字符,即 Emacs 识别为帮助含义的字符。默认值为 8,对应 C-h。当 Emacs 读取该字符时,若 help-form 为非 nil 的 Lisp 表达式,则求值该表达式,若结果为字符串则在框架中显示。
通常 help-form 为 nil,此时帮助字符在命令输入层无特殊含义,会按常规方式成为按键序列的一部分。C-h 的标准绑定是多个通用帮助功能的前缀键。
帮助字符在前缀键之后也具有特殊性。若其在前缀键下无子命令绑定,则运行 describe-prefix-bindings,显示该前缀键的所有子命令列表。
该变量的值为事件类型列表,用作备用帮助字符。这些事件的处理方式与 help-char 指定的事件相同。
若该变量非 nil,则每当读取到 help-char 字符时,就会求值其值对应的表达式。若求值结果为字符串,则显示该字符串。
调用 read-event、read-char-choice、read-char、read-char-from-minibuffer 或 y-or-n-p 的命令,在执行输入时通常应将 help-form 绑定为非 nil 表达式(C-h 另有含义时除外)。该表达式的求值结果应为字符串,说明输入用途与正确输入方式。
进入小框架时,该变量会被绑定为 minibuffer-help-form 的值(see Definition of minibuffer-help-form)。
该变量保存用于打印前缀键帮助的函数。当用户输入前缀键后紧跟帮助字符,且帮助字符在该前缀下无绑定时调用。变量默认值为 describe-prefix-bindings。
该函数调用 describe-bindings 显示最近按键序列中前缀键的所有子命令列表。所描述的前缀由该按键序列除最后一个事件外的所有事件组成(最后一个事件通常为帮助字符)。
以下两个函数面向希望在不交出控制权的情况下提供帮助的模式(如电子模式)设计。其名称以 ‘Helper’ 开头,以与普通帮助函数区分。
该命令弹出一个框架,显示包含局部与全局按键映射所有绑定的帮助框架。其通过调用 describe-bindings 实现。
该命令为当前模式提供帮助。它在小框架中提示用户 ‘Help (Type ? for further options)’,然后协助用户查询按键绑定与模式用途。返回 nil。
可通过修改映射 Helper-help-map 进行自定义。
该变量保存 Emacs 查找其附带的特定文档与文本文件的目录名。
该函数返回帮助框架的名称,通常为 *Help*;若该框架不存在,则先创建再返回。
该宏与 with-output-to-temp-buffer 类似地求值 body(see Temporary Displays),并将其表单产生的输出插入 buffer-or-name 指定的框架中(buffer-or-name 可为框架或框架名,常用值为 help-buffer 函数返回结果)。该宏将指定框架设为帮助模式,并显示提示信息告知用户如何退出与滚动帮助窗口。若用户选项 help-window-select 已相应设置,则选中帮助窗口。返回 body 中最后一个表达式的值。
该函数更新 *Help* 框架中的交叉引用数据,用于用户点击 ‘Back’ 或 ‘Forward’ 按钮时重新生成帮助信息。大多数使用 *Help* 框架的命令在清空框架前都应调用此函数。item 参数格式应为 (function . args),其中 function 为重新生成帮助框架所需调用的函数,args 为参数列表。若调用命令为交互式执行,则 interactive-p 非 nil,此时 *Help* 框架的 ‘Back’ 按钮历史栈会被清空。
使用 help-buffer、with-help-window 与 help-setup-xref 的示例参见 See describe-symbols example。
该宏定义名为 fname 的帮助命令,行为类似前缀键,显示其所提供子命令的列表。
调用时,fname 在窗口中显示 help-text,然后根据 help-map 读取并执行按键序列。字符串 help-text 应描述 help-map 中可用的绑定。
命令 fname 自身处理部分事件,用于滚动 help-text 显示。当 fname 读取到这类特殊事件时,执行滚动并继续读取下一个事件。当读取到不属于此类且在 help-map 中有绑定的事件时,执行该按键绑定并返回。
参数 help-line 应为 help-map 中可选操作的单行摘要。在当前 Emacs 版本中,仅当将选项 three-step-help 设为 t 时才会使用该参数。
该宏用于命令 help-for-help,其绑定为 C-h C-h。
若该变量非 nil,则由 make-help-screen 定义的命令会先在回显区显示 help-line 字符串,仅当用户再次输入帮助字符时才显示较长的 help-text 字符串。
Emacs 可以按照不同分组列出函数。例如,string-trim 和 mapconcat 都属于“字符串”函数,
因此执行 M-x shortdoc RET string RET 可以概览所有操作字符串的函数。
文档分组通过 define-short-documentation-group 宏定义。
将 group 定义为一个函数分组,并提供这些函数的简要用法说明。可选参数 functions 是一个列表, 每个元素格式如下:
(func [keyword val]...)
The following keywords are recognized:
:eval取值应为一个求值时无副作用的表达式。该表达式会通过 prin1 打印并显示在文档中(see 输出函数)。
如果表达式是字符串,则会原样插入,之后再通过 read 解析为表达式。无论哪种形式,最终都会被求值并展示结果。例如:
:eval (concat "foo" "bar" "zot") :eval "(make-string 5 ?x)"
会生成如下显示:
(concat "foo" "bar" "zot") ⇒ "foobarzot" (make-string 5 ?x) ⇒ "xxxxx"
(此处同时支持 Lisp 表达式和字符串,是为了在少数需要精确控制表达式展示形式的场景下使用。 例如上例中,如果不放在字符串里,‘?x’ 会被打印成 ‘120’。)
:no-eval与 :eval 类似,但不会对表达式求值。这种情况下通常需要搭配某种 :result 系列关键字(见下文)。
:no-eval (file-symlink-p "/tmp/foo") :eg-result t
:no-eval*与 :no-eval 类似,但结果固定显示为 ‘[it depends]’。例如:
:no-eval* (buffer-string)
会生成:
(buffer-string) → [it depends]
:no-value与 :no-eval 类似,用于函数没有明确定义返回值、仅用于产生副作用的场景。
:result用于为不求值的示例表达式指定输出结果。
:no-eval (setcar list 'c) :result c
:eg-result用于为不求值的示例表达式输出示例结果。例如:
:no-eval (looking-at "f[0-9]") :eg-result t
会生成:
(looking-at "f[0-9]") eg. → t
:result-string:eg-result-string分别与 :result 和 :eg-result 作用相同,但会原样插入字符串。
适用于结果不可读或需要特定格式的场景:
:no-eval (find-file "/tmp/foo") :eg-result-string "#<buffer foo>" :no-eval (default-file-modes) :eg-result-string "#o755"
:no-manual表示该函数未在手册中专门说明。
:args默认显示函数实际的参数列表。如果指定了 :args,则使用此处给出的参数列表。
:args (regexp string)
一个极简示例:
(define-short-documentation-group string "Creating Strings" (substring :eval (substring "foobar" 0 3) :eval (substring "foobar" 3)) (concat :eval (concat "foo" "bar" "zot")))
第一个参数是要定义的分组名称,之后可以跟随任意数量的函数说明。
一个函数可以属于任意多个文档分组。
除函数说明外,列表中还可以包含字符串元素,用于将一个文档分组划分为多个小节。
Lisp 包可以使用该函数向分组中添加函数。每个 elem 应为上文所述格式的函数说明。 group 为目标函数分组,section 为要插入到该分组中的小节名称。
如果 group 不存在,则会自动创建。如果 section 不存在,则会添加到函数分组的末尾。
你也可以查询在 shortdoc 分组中定义的函数用法示例。
该函数返回 function 的所有 shortdoc 示例。返回值为一个关联列表,元素格式为
(group . examples),其中 group 是该函数所属的文档分组,
examples 是一个字符串,包含该分组中定义的函数用法示例。
如果 function 不是函数,或者没有任何 shortdoc 示例,则 shortdoc-function-examples 返回 nil。
该函数查询已注册的 shortdoc 分组,并将指定 Emacs Lisp 函数 function 的用法示例插入到当前框架中。
它适合添加到 help-fns-describe-function-functions 钩子中,这样在查看函数文档时,
shortdoc 中的用法示例会显示在 *Help* 框架里。
本章介绍用于查找、创建、查看、保存以及以其他方式操作文件和目录的 Emacs Lisp 函数与变量。另有一些与文件相关的函数,见缓冲区,与备份和自动保存相关的内容,见备份与自动保存。
多数文件函数会接受一个或多个文件名参数。文件名是一个字符串。这些函数大多会通过 expand-file-name 函数展开文件名参数,从而正确处理 ~ 以及相对文件名(包括 ../ 和空字符串)。See 文件名展开相关函数。
此外,某些 魔术(magic)文件名会被特殊处理。例如,当指定远程文件名时,Emacs 会通过合适的协议经由网络访问该文件。See Remote Files in The GNU Emacs Manual。这类处理在底层完成,因此你可以假定本章描述的所有函数均接受魔术文件名作为文件名参数,除非另有说明。See 实现“魔法”文件名机制。
当文件 I/O 函数触发 Lisp 错误时,通常使用 file-error 条件(see 编写处理错误的代码)。错误信息大多取自操作系统,依据区域设置 system-messages-locale 并通过编码系统 locale-coding-system 解码(see Locales)。
访问文件指将文件读入一个框架。完成此操作后,我们称该框架正在访问(visiting)该文件,并将该文件称为该框架的被访问文件(the visited file)。
文件与框架是两个不同的概念。文件是永久保存在计算机中的信息(除非你将其删除)。而框架则是 Emacs 内部的信息,会在编辑会话结束时(或你销毁框架时)消失。当框架正在访问某个文件时,其中包含从该文件复制而来的内容。你通过编辑命令修改的是框架中的副本。对框架的修改不会直接改变文件;要使修改永久生效,必须保存(save)框架,即将修改后的框架内容写回文件。
尽管文件与框架存在区别,人们在表述时常常混用二者,说文件时实际指框架,反之亦然。我们通常会说 “我正在编辑一个文件”,而非 “我正在编辑一个框架,稍后会将其保存为同名文件”。日常交流中通常无需明确区分。但在编写计算机程序时,则应牢记二者的区别。
本节介绍通常用于访问文件的函数。由于历史原因,这些函数的名称以 ‘find-’ 开头,而非 ‘visit-’。有关获取框架的被访问文件名、或根据被访问文件名查找已有框架的函数与变量,参见 Buffer File Name。
在 Lisp 程序中,若你只想查看文件内容而不修改它,最快的方式是在临时框架中使用 insert-file-contents。访问文件并非必需,且速度更慢。参见 从文件读取。
该命令选中一个访问文件 filename 的框架;若已有对应框架则直接使用,否则创建新框架并将文件读入其中。它同时返回该框架。
除一些技术细节外,find-file 函数的主体大致等价于:
(switch-to-buffer (find-file-noselect filename nil nil wildcards))
(参见 Switching to a Buffer in a Window 中的 switch-to-buffer。)
若 wildcards 非 nil(交互式调用时恒为真),则 find-file 会展开 filename 中的通配符,并访问所有匹配的文件。
当以交互式方式调用 find-file 时,它会在迷你缓冲区中提示输入 filename。
该命令与 find-file 类似,会访问 filename,但不执行任何格式转换(see 文件格式转换)、字符编码转换(see Coding Systems)或行尾转换(see End of line conversion)。
访问该文件的框架会被设为单字节模式,且主模式为基本模式,与文件名无关。文件中的文件局部变量设置(see 文件局部变量)会被忽略;同时禁用自动解压,以及因 require-final-newline(see require-final-newline)在文件末尾自动添加换行的行为。
注意:若 Emacs 中已有以普通方式访问同一文件的框架,则不会以字面量方式重新访问,而是直接切换到已有框架。若你确保以字面量方式读取文件内容,应创建临时框架,再使用 insert-file-contents-literally 将文件内容读入其中(see 从文件读取)。
该函数是所有文件访问函数的核心。它返回一个访问文件 filename 的框架。你可以自行将该框架设为当前框架或在窗口中显示,但该函数本身不会这样做。
若已有对应框架,函数会直接返回该框架;否则创建新框架并读入文件。当 find-file-noselect 使用已有框架时,会先检查文件自上次在该框架中访问或保存后是否被修改(除非 nowarn 非 nil,见下文)。若文件已变更,函数会询问用户是否重新读取已修改的文件。若用户选择 ‘yes’,框架中此前的编辑内容将丢失。
读取文件过程包括对文件内容进行解码(see Coding Systems),其中包含行尾转换与格式转换(see 文件格式转换)。若 wildcards 非 nil,则 find-file-noselect 会展开 filename 中的通配符,并访问所有匹配的文件。
该函数会在多种特殊情况下显示警告或提示信息,除非可选参数 nowarn 非 nil。例如,当需要创建框架但不存在名为 filename 的文件时,它会在回显区显示信息 ‘(New file)’,并保持框架为空。若 nowarn 非 nil,文件上次修改时间的校验也会被跳过。
find-file-noselect 通常在读取文件后调用 after-find-file(see 访问文件的子例程)。该函数会设置框架主模式、解析局部变量,若存在比刚访问文件更新的自动保存文件则提醒用户,最后运行 find-file-hook 中的函数。
若可选参数 rawfile 非 nil,则不会调用 after-find-file,文件不存在时也不会运行 find-file-not-found-functions。此外,非 nil 的 rawfile 会禁用编码系统转换与格式转换。
find-file-noselect 通常返回访问文件 filename 的框架。但如果实际使用并展开了通配符,则返回一个访问各对应文件的框架列表。
(find-file-noselect "/etc/fstab")
⇒ #<buffer fstab>
该命令选中访问文件 filename 的框架,但会在当前选中窗口之外的另一窗口中显示。它可能使用已有其他窗口或拆分窗口,参见 Switching to a Buffer in a Window。
以交互式方式调用该命令时,会提示输入 filename。
该命令与 find-file 类似,选中访问文件 filename 的框架,但会将框架标记为只读。相关函数与变量参见 Read-Only Buffers。
以交互式方式调用该命令时,会提示输入 filename。
若该变量非 nil,则各个 find-file 命令会检查通配符并访问所有匹配的文件(交互式调用或其 wildcards 参数非 nil 时)。若该选项为 nil,则 find-file 系列命令会忽略 wildcards 参数,永远不会特殊处理通配符。
该变量的值是一个函数列表,会在访问文件后被调用。钩子运行前,文件的局部变量设置(若有)已被处理完毕。钩子函数运行时,访问该文件的框架为当前框架。
该变量是一个常规钩子。参见 钩子。
该变量的值是一个函数列表,当 find-file 或 find-file-noselect 传入不存在的文件名时会被调用。find-file-noselect 检测到文件不存在时会立即按列表顺序调用这些函数,直到其中一个返回非 nil。此时 buffer-file-name 已经设置完成。
它并非常规钩子,因为函数的返回值会被使用,且多数情况下只会调用列表中的部分函数。
该框架局部变量若被设为非 nil 值,会使 save-buffer 表现为框架以字面量方式访问文件,即不进行任何格式转换。命令 find-file-literally 会设置该变量的局部值,其他等效函数与命令也可如此设置,例如避免在文件末尾自动添加换行。该变量为永久局部变量,因此不会随主模式切换而改变。
find-file-noselect 函数使用两个重要子例程,它们在用户 Lisp 代码中有时也很有用:create-file-buffer 与 after-find-file。本节说明它们的用法。
该函数为访问 filename 创建一个名称合适的框架并返回。若名称未被占用,则直接使用 filename(不含目录部分);否则附加类似 ‘<2>’ 的字符串以获得未占用名称。另见 Creating Buffers。 注意 uniquify 库会影响该函数的结果。参见 See Uniquify in The GNU Emacs Manual。
注意: create-file-buffer 不会将新框架与文件关联,也不会选中该框架。它同样不会使用默认主模式。
(create-file-buffer "foo")
⇒ #<buffer foo>
(create-file-buffer "foo")
⇒ #<buffer foo<2>>
(create-file-buffer "foo")
⇒ #<buffer foo<3>>
该函数被 find-file-noselect 使用。
它内部调用 generate-new-buffer(see Creating Buffers)。
该函数设置框架主模式,并解析局部变量(see Emacs 如何选择主模式)。它由 find-file-noselect 与默认的恢复函数调用(see 恢复缓冲区)。
若因文件不存在(但其所在目录存在)导致读取文件出错,调用方应为 error 传入非 nil 值。此时 after-find-file 会发出警告:‘(New file)’。若为更严重的错误,调用方通常不应调用 after-find-file。
若 warn 非 nil,当存在比被访问文件更新的自动保存文件时,该函数会发出警告。
若 noauto 非 nil,表示不启用或禁用自动保存模式。该模式会保持之前的启用状态不变。
若 after-find-file-from-revert-buffer 非 nil,表示本次调用来自 revert-buffer。该参数本身无直接效果,但部分模式函数与钩子函数会检查其值。
若 nomodes 非 nil,表示不修改框架主模式、不处理文件中的局部变量设置、不运行 find-file-hook。该特性在某些情况下被 revert-buffer 使用。
after-find-file 执行的最后一步是调用列表 find-file-hook 中的所有函数。
在 Emacs 中编辑文件时,你实际操作的是访问该文件的缓冲区——也就是说,文件内容会被复制到缓冲区中,你编辑的是这份副本。对缓冲区的修改不会直接写入文件,除非你保存缓冲区,即将缓冲区内容回写到文件中。对于未访问任何文件的缓冲区,在某种意义上仍可借助缓冲区局部的 write-contents-functions 钩子函数实现 “保存(saved)”。
该函数会在当前缓冲区自上次访问或保存后被修改过的情况下,将其内容保存到对应的访问文件中;否则不执行任何操作。
save-buffer 负责创建备份文件。通常情况下,backup-option 为 nil,且 save-buffer 仅在访问文件后的首次保存时创建备份。backup-option 取其他值时,会在不同场景下要求生成备份文件:
save-buffer 会标记该文件版本,在缓冲区下次保存时执行备份。
save-buffer 会在保存前无条件为文件的旧版本创建备份。
该命令用于保存部分已修改的、访问文件的缓冲区。默认情况下会逐一询问用户;但若 save-silently-p 非 nil,则直接保存所有访问文件的缓冲区,不向用户确认。
可选参数 pred 是一个谓词函数,用于控制需要询问(或在 save-silently-p 非空时静默保存)的缓冲区。若 pred 为 nil,则使用 save-some-buffers-default-predicate 的值替代。若结果为 nil,表示仅询问访问文件的缓冲区;若为 t,则额外提供保存某些非文件缓冲区的选项——即缓冲区局部变量 buffer-offer-save 非 nil 的缓冲区(see Killing Buffers)。用户确认保存此类非文件缓冲区时,会被要求指定保存的文件名。save-buffers-kill-emacs 函数会为 pred 传入 t。
若谓词既非 t 也非 nil,则应为无参函数。该函数会在每个缓冲区中执行,以判断是否提供保存选项;若在某缓冲区中返回非空值,则表示对该缓冲区询问保存。
该函数将当前缓冲区内容写入文件 filename,使缓冲区关联该文件,并标记缓冲区为未修改状态。随后会根据 filename 重命名缓冲区,必要时附加类似 ‘<2>’ 的字符串以保证缓冲区名称唯一。其核心工作通过调用 set-visited-file-name(see Buffer File Name)和 save-buffer 完成。
若 confirm 非 nil,则在覆盖已有文件前要求用户确认。交互模式下默认需要确认,除非用户使用前缀参数。
若 filename 为目录名(see 目录名),write-file 会在该目录下使用原访问文件的文件名;若缓冲区未访问任何文件,则使用缓冲区名作为文件名。
保存缓冲区时会运行若干钩子,并执行格式转换(see 文件格式转换)。需要注意的是,下述钩子仅由 save-buffer 触发,其他将缓冲区内容写入文件的底层函数或工具不会运行这些钩子;尤其自动保存功能(see 自动保存)不会触发。
该变量的值是一组函数列表,会在将缓冲区写入对应访问文件前依次调用。若其中某函数返回非空值,则视为文件已写入完成,后续函数不再执行,常规的文件写入逻辑也不再运行。
若 write-file-functions 中的函数返回非空值,则需自行负责创建备份文件(如适用),可执行以下代码:
(or buffer-backed-up (backup-buffer))
建议保存 backup-buffer 返回的文件权限值,并在写入文件时使用该值(非空时),这也是 save-buffer 的默认行为。See Making Backup Files。
write-file-functions 中的钩子函数还需负责数据编码(如需):选择合适的编码系统与行尾转换规则(see Coding Systems in Lisp),执行编码操作(see Explicit Encoding and Decoding),并将 last-coding-system-used 设置为实际使用的编码系统(see Encoding and I/O)。
若在缓冲区中局部设置该钩子,系统会认为其与文件或缓冲区内容的获取方式相关。因此该变量被标记为永久局部变量,切换主模式不会改变其缓冲区局部值;但调用 set-visited-file-name 会重置该值。若不符合预期,可改用 write-contents-functions。
尽管该变量并非常规钩子,仍可使用 add-hook 和 remove-hook 管理列表。See 钩子。
用法与 write-file-functions 类似,但适用于与缓冲区内容相关、而非与特定访问文件或路径相关的钩子,可用于为完全不关联文件的缓冲区实现自定义保存流程。此类钩子通常由主模式设置为该变量的缓冲区局部绑定。该变量一经设置即自动成为缓冲区局部变量;切换主模式会重置该变量,但调用 set-visited-file-name 不会。
若该钩子列表中任意函数返回非空值,则视为文件已写入,后续函数以及 write-file-functions 中的函数均不再执行。
使用该钩子保存无关联文件的缓冲区(如特殊模式缓冲区)时需注意:若函数保存失败并返回 nil,save-buffer 会继续提示用户指定保存文件的路径。若不希望出现此行为,可让函数通过抛出错误终止执行。
该常规钩子会在缓冲区保存到对应访问文件前运行,无论保存是通过常规方式还是上述钩子完成。例如,copyright.el 程序借助该钩子确保保存文件的版权声明中使用当前年份。
该常规钩子会在缓冲区成功保存到对应访问文件后运行。
若该变量非 nil,save-buffer 会在保存时防范 I/O 错误:先将新文件写入临时文件名,确认无错误后再重命名为目标文件名。该机制可避免因磁盘空间不足等问题导致文件损坏。
副作用是备份文件必须通过复制生成。See 备份方式:重命名还是复制?。同时,保存重要文件时会断开该文件与其他文件名的所有硬链接。
部分模式会在特定缓冲区中将该变量设为非空的缓冲区局部值。
该变量控制文件写入时是否允许末尾无换行符。若值为 t,save-buffer 会在缓冲区末尾无换行时静默添加;若为 visit,Emacs 仅在访问文件时补充缺失的换行;若为 visit-save,则访问与保存时均会补充;其他非空值下,save-buffer 会在每次遇到此类情况时询问用户是否添加换行。
若变量值为 nil,save-buffer 完全不自动添加换行。nil 为默认值,但部分主模式会在特定缓冲区中将其设为 t。
另请参见函数 set-visited-file-name(see Buffer File Name)。
将文件内容复制到缓冲区,可使用函数 insert-file-contents。(Lisp 程序中请勿使用命令 insert-file,该命令会设置标记。)
该函数在当前缓冲区的点后插入文件 filename 的内容,返回包含文件绝对路径与插入数据长度的列表。若 filename 不是可读文件,则抛出错误。
该函数会根据预设文件格式检查并转换文件内容,同时调用 after-insert-file-functions 列表中的函数。See 文件格式转换。通常,列表中的某一函数会确定解码文件内容所用的编码系统(see Coding Systems),包括行尾转换。但若文件包含空字节,默认情况下访问时不执行任何编码转换。See inhibit-null-byte-detection。
若 visit 非 nil,该函数会额外将缓冲区标记为未修改,并设置缓冲区相关字段使其关联文件 filename,包括缓冲区访问文件名与上次保存的文件修改时间。该功能由 find-file-noselect 使用,一般不建议直接调用。
若 beg 与 end 非空,应为字节偏移量,指定插入文件的片段;此时 visit 必须为 nil。例如:
(insert-file-contents filename nil 0 500)
会插入文件前 500 字节对应的字符内容。
若 beg 或 end 落在字符多字节序列中间,Emacs 的字符编码转换会向缓冲区插入一个或多个 8 位字符(又称 “原始字节(raw bytes)”)(see Character Sets)。若需以此方式读取文件片段,建议在调用该函数时将 coding-system-for-read 绑定为合适的值(see Specifying a Coding System for One Operation),并编写代码检查边界处的原始字节,读取完整字节序列后转换为合法字符。
若参数 replace 非 nil,表示用文件内容替换缓冲区(实际为可访问区域)内容。该方式优于先删除再整体插入,原因在于:1)保留部分标记位置;2)减少撤销记录中的数据量。
insert-file-contents 可读取特殊文件(如管道、I/O 设备),条件是 replace 为 nil 或 if-regular,且 visit 与 beg 为 nil。但此类文件通常需指定 end 参数,避免向缓冲区插入无限长度数据(例如读取 /dev/urandom)。
该函数用法与 insert-file-contents 一致,区别在于逐字节处理文件内容,必要时直接转换为 8 位字符。它不会运行 after-insert-file-functions,不执行格式解码、字符编码转换、自动解压等操作。
若需将文件名传递给其他进程供外部程序读取,可使用函数 file-local-copy,参见 实现“魔法”文件名机制。
可以使用 append-to-file 和 write-region 函数,将缓冲区或缓冲区部分内容直接写入磁盘文件。请勿使用这些函数写入正被访问的文件,否则可能导致文件访问机制出现混乱。
该函数将当前缓冲区中由 start 和 end 限定的区域内容追加到文件 filename 末尾。若文件不存在,则自动创建。函数返回 nil。
若无法写入或创建 filename,则抛出错误。
从 Lisp 调用时,该函数完全等价于:
(write-region start end filename t)
该函数将当前缓冲区中由 start 和 end 限定的区域内容写入文件 filename。
若 start 为 nil,则命令将整个缓冲区内容(并非仅可访问部分)写入文件,并忽略 end。
若 start 为字符串,则 write-region 直接写入或追加该字符串,而非缓冲区文本,此时忽略 end。
若 append 非 nil,则将指定文本追加到现有文件内容(若存在)之后。若 append 为数字,write-region 会从文件开头偏移该数字对应的字节位置开始写入数据。
若 mustbenew 非 nil,当 filename 已存在时,write-region 会要求用户确认。若 mustbenew 为符号 excl,则不询问确认,而是在文件已存在时抛出 file-already-exists 错误。通常 write-region 会跟随符号链接,并在符号链接悬空时创建指向的目标文件;但当 mustbenew 为 excl 时,不会跟随符号链接。
当 mustbenew 为 excl 时,对文件是否存在的检测使用系统专用特性。至少对本地磁盘文件而言,不会出现其他程序在 Emacs 之前创建同名文件而 Emacs 无法察觉的情况。
若 visit 为 t,Emacs 会在当前缓冲区与该文件之间建立关联,即缓冲区开始访问此文件。同时会将当前缓冲区的上次文件修改时间设为 filename 的修改时间,并将缓冲区标记为未修改。该功能由 save-buffer 使用,一般不建议自行调用。
若 visit 为字符串,则指定要关联的文件名。这样可以将数据写入文件 filename,同时记录缓冲区访问的是另一个文件 visit。参数 visit 会用于回显区提示信息与文件加锁,并保存在 buffer-file-name 中。该功能用于实现 file-precious-flag,除非完全明确其用途,否则请勿自行使用。
可选参数 lockname 若非 nil,则指定用于文件加锁与解锁的文件名,覆盖 filename 与 visit 的相关设置。
write-region 函数会根据 buffer-file-format 指定的格式转换待写入数据,并调用 write-region-annotate-functions 列表中的函数。See 文件格式转换。
默认情况下,write-region 会在回显区显示 ‘Wrote filename’ 信息。若 visit 既非 t、非 nil 也非字符串,或 Emacs 运行在批处理模式下(see Batch Mode),则不显示该信息。该特性适用于程序内部使用、无需用户知晓的文件操作。
若该变量值为 nil,write-region 在写入文件后会调用 fsync 系统调用。若值为 t,则不使用 fsync。默认值为 t。See 文件与辅助存储。
宏 with-temp-file 使用临时缓冲区作为当前缓冲区执行 body 中的表达式;执行完毕后,将缓冲区内容写入文件 file。完成后销毁临时缓冲区,并恢复执行 with-temp-file 之前的当前缓冲区。最终返回 body 中最后一个表达式的值。
即使通过 throw 或错误异常退出(see 非局部退出),当前缓冲区也会被正确恢复。
与 with-temp-buffer(see Current Buffer)类似,该宏使用的临时缓冲区不会运行钩子 kill-buffer-hook、kill-buffer-query-functions(see Killing Buffers)以及 buffer-list-update-hook(see The Buffer List)。
当两名用户同时编辑同一个文件时,很可能会互相干扰。Emacs 会在文件被修改时记录一个文件锁,以此避免这种情况发生。
Emacs 能够在首次尝试修改被其他 Emacs 进程锁定的文件所对应的缓冲区时检测到冲突,并询问用户如何处理。
文件锁本质上是一个文件,即一个具有特殊名称的符号链接,存放在你正在编辑的文件所在目录中。其命名规则是在缓冲区对应的文件名前添加 .#。
该符号链接的目标格式为 user@host.pid:boot,其中 user 为当前用户名(取自 user-login-name),host 为运行 Emacs 的主机名(取自 system-name),pid 为 Emacs 进程 ID,boot 为系统上次启动以来的时间。若无法获取启动时间,则省略 :boot。(在不支持符号链接的文件系统上,会改用普通文件实现,内容格式同上。)
使用 NFS 访问文件时,存在极小概率会出现你与另一名用户同时为同一个文件加锁的情况。 即便发生这种情况,两人仍可同时修改文件,但 Emacs 仍会对后保存的用户发出警告。 此外,检测缓冲区所访问的文件在磁盘上已被修改的机制也能发现部分同时编辑的情形,详见 Buffer Modification Time。
若文件 filename 未被锁定,该函数返回 nil。若被当前 Emacs 进程锁定则返回 t,若被其他进程锁定则返回持有锁的用户名。
(file-locked-p "foo")
⇒ nil
若当前缓冲区已被修改,该函数会为文件 filename 加锁。参数 filename 默认为当前缓冲区所访问的文件。若当前缓冲区未访问任何文件、未被修改,或选项 create-lockfiles 为 nil,则不执行任何操作。
该函数为当前缓冲区所访问的文件解锁,前提是缓冲区已被修改。若缓冲区未被修改,则文件本不应加锁,函数不执行任何操作。若当前缓冲区未访问文件或文件未被锁定,同样不执行操作。
该函数会通过调用 display-warning 处理文件系统错误,除此之外忽略该错误。
若该变量为 nil,Emacs 不会为文件加锁。
默认情况下,Emacs 在被锁定文件所在的同一目录下创建锁文件。可通过自定义该变量修改这一行为。其语法与 auto-save-file-name-transforms 相同(see 自动保存)。例如,若想让 Emacs 将所有锁文件写入 /var/tmp/,可使用如下配置:
(setq lock-file-name-transforms
'(("\\`/.*/\\([^/]+\\)\\'" "/var/tmp/\\1" t)))
当用户尝试修改文件 file,但该文件已被名为 other-user 的其他用户锁定时,会调用此函数。该函数的默认实现会询问用户如何处理,其返回值决定 Emacs 后续行为:
t 表示强行夺取文件锁。当前用户即可编辑该文件,原锁定用户 other-user 失去锁。
nil 表示忽略锁,仍允许当前用户编辑文件。
file-locked 错误,此时用户即将执行的修改不会生效。
该错误的提示信息格式如下:
error→ File is locked: file other-user
其中 file 为文件名,other-user 为锁定该文件的用户名。
如有需要,你可以重新定义 ask-user-about-lock 函数,以其他方式决策冲突处理方式。
将变量 remote-file-name-inhibit-locks 设置为 t,可禁止为远程文件创建锁文件。
该命令以交互方式调用时,切换当前缓冲区中 create-lockfiles 的局部值。
本节介绍用于获取文件(或目录、符号链接)各类信息的函数,例如文件是否可读、可写,以及文件大小等。这些函数均以文件名作为参数。除特别注明外,这些参数必须指向已存在的文件,否则会抛出错误。
使用以空格结尾的文件名时需格外小心。在部分文件系统(尤其是 MS-Windows)上,文件名末尾的空白字符会被静默自动忽略。
这些函数用于测试访问文件的权限,包括读取、写入或执行权限。除非另有明确说明,否则它们会跟随符号链接。See 区分文件类型。
在部分操作系统中,可通过访问控制列表(ACL)等机制配置更复杂的访问权限集。 有关如何查询和设置这些权限的方法,详见 See 文件扩展属性。
若名为 filename 的文件看似存在,该函数返回 t。这仅表示你大概率能获取文件属性,而非一定能读取文件内容。
(在 GNU 及其他类 POSIX 系统中,只要文件存在且你拥有其所在目录的执行权限,无论文件自身权限如何,该函数均返回 t。)
若文件不存在,或无法确定文件是否存在,该函数返回 nil。
空字符串文件名会被解析为相对于当前缓冲区的默认目录(see 绝对文件名与相对文件名),因此向 file-exists-p 传入空字符串时,实际检测的是缓冲区默认目录的存在性。
目录本质上也是文件,因此向 file-exists-p 传入目录名时可能返回 t。但由于该函数会跟随符号链接,仅当链接目标存在时,符号链接名才会返回 t;
若你的 Lisp 程序需要将目标不存在的悬空符号链接(dangling symlinks)视为已存在的文件,请使用 file-attributes(see 文件属性)而非 file-exists-p。
若名为 filename 的文件存在且你拥有读取权限,该函数返回 t;否则返回 nil。
若名为 filename 的文件存在且你拥有执行权限,该函数返回 t;否则返回 nil。
在 GNU 及其他类 POSIX 系统中,若文件是目录,执行权限意味着你可检查目录内文件的存在性和属性,且在文件自身权限允许的情况下打开这些文件。
若你可写入或创建文件 filename,该函数返回 t;否则返回 nil。
文件可写的条件:文件已存在且你拥有写入权限;文件不存在但其父目录存在且你拥有该目录的写入权限(即可创建文件)。
下述示例中,foo 不可写,原因是其父目录不存在——即便用户有权创建该目录,函数仍返回 nil。
(file-writable-p "~/no-such-dir/foo")
⇒ nil
若你拥有打开目录 dirname 内已有文件的权限,该函数返回 t;否则(如目录不存在)返回 nil。
参数 dirname 可以是目录名(如 /foo/),也可以是目录对应的文件名(如 /foo,无末尾斜杠)。
例如,从以下结果可推断:尝试读取 /foo/ 内的任何文件都会触发错误:
(file-accessible-directory-p "/foo")
⇒ nil
该宏确保在执行 body 中的表达式前,default-directory 已绑定到一个已存在的目录。
若 default-directory 本身已存在,则优先使用;否则会选用其他已存在的目录。
该宏适用于调用要求运行目录必须存在的外部命令等场景,但不保证所选目录可写。
若你可读取 filename,该函数返回 nil;否则抛出错误,错误提示文本为 string。
若用户选项 remote-file-name-access-timeout 设为正数,当函数执行时间超过该值(单位:秒)时会抛出错误。
该限制仅适用于远程文件,且不计入读取密码等额外耗时。
若删除文件 filename 后重新创建,其所有者保持不变,该函数返回 t;对于不存在的文件,同样返回 t。
若可选参数 group 非 nil,该函数还会检查文件的所属组是否保持不变。
该函数不跟随符号链接。
该函数返回文件 filename 的模式位(mode bits)——即汇总文件读、写、执行权限的整数。
该函数默认跟随符号链接;若文件不存在,返回值为 nil。
有关模式位的详细说明,详见 See File permissions in The GNU Coreutils Manual。
例如,最低位为 1 表示所有用户均可执行该文件;次低位为 1 表示所有用户均可写入该文件,依此类推。
模式位的最大值为 4095(八进制 7777),表示所有人拥有读、写、执行权限,同时为其他用户和组设置了 SetUID 位,且设置了粘滞位。
默认情况下该函数跟随符号链接;但若可选参数 flag 为符号 nofollow,则当 filename 是符号链接时不跟随,
这可避免意外获取其他位置文件的模式位,且与 file-attributes(see 文件属性)的行为更一致。
有关设置文件权限的方法,详见 See 修改文件名与属性 中的 set-file-modes 函数。
(file-modes "~/junk/diffs" 'nofollow)
⇒ 492 ; Decimal integer.
(format "%o" 492)
⇒ "754" ; Convert to octal.
(set-file-modes "~/junk/diffs" #o666 'nofollow)
⇒ nil
$ ls -l diffs -rw-rw-rw- 1 lewis lewis 3063 Oct 30 16:00 diffs
MS-DOS 说明:MS-DOS 系统无“可执行文件模式位”概念。因此 file-modes 会根据文件名后缀判断文件是否可执行——
若后缀为 .com、.bat、.exe 等标准可执行扩展名,则视为可执行文件;
以 POSIX 标准 ‘#!’ 开头的文件(如 Shell 脚本、Perl 脚本)也被视为可执行;
为兼容 POSIX,目录同样会被标记为可执行。file-attributes(see 文件属性)也遵循这些约定。
本节介绍如何区分不同类型的文件,例如目录、符号链接和普通文件。
符号链接在大多数场景下都会被自动解析(跟随)。例如解析文件名 a/b/c 时,a、a/b、a/b/c 中的任意一个都可能是会被解析的符号链接,若链接目标本身也是符号链接,还可能递归解析。 但有少数函数不会解析文件名末尾的符号链接(如本例中的 a/b/c),这类函数被称为不跟随符号链接(not follow symbolic links)。
若文件 filename 是符号链接,该函数不会解析它,而是以字符串形式返回其链接目标。 (链接目标字符串不一定是目标文件的完整绝对路径;要确定链接指向的完整路径并非易事,详见下文。)
若文件 filename 不是符号链接、不存在,或无法确定其是否为符号链接,file-symlink-p 返回 nil。
以下是该函数的使用示例:
(file-symlink-p "not-a-symlink")
⇒ nil
(file-symlink-p "sym-link")
⇒ "not-a-symlink"
(file-symlink-p "sym-link2")
⇒ "sym-link"
(file-symlink-p "/bin")
⇒ "/pub/bin"
注意第三个示例中,函数仅返回 sym-link,并未继续解析该文件(尽管它本身也是符号链接)。 这是因为该函数不跟随符号链接——符号链接解析过程不会作用于文件名的最后一个组成部分。
该函数返回的字符串是符号链接中记录的原始内容,可能包含或不包含前缀目录。 该函数不会将链接目标展开为全限定路径;尤其当链接目标不是绝对路径时,不会将 filename 参数中的前缀目录(若有)拼接到目标前。示例如下:
(file-symlink-p "/foo/bar/baz")
⇒ "some-file"
本例中,尽管传入的是全限定路径 /foo/bar/baz,但返回结果并非全路径,甚至完全没有前缀目录。
且由于 some-file 本身也可能是符号链接,你无法简单地为其添加前缀目录,也不能直接使用 expand-file-name(see 文件名展开相关函数)生成其绝对路径。
因此,若你仅需判断文件是否为符号链接,该函数适用;若需要获取链接目标的完整文件名,应使用 真实路径 中介绍的 file-chase-links 或 file-truename。
若 filename 是已存在目录的名称,该函数返回 t;若 filename 不是目录名、目录不存在,或无法确定其是否为目录,则返回 nil。
该函数会跟随符号链接。
(file-directory-p "~rms")
⇒ t
(file-directory-p "~rms/lewis/files.texi")
⇒ nil
(file-directory-p "~rms/lewis/no-such-file")
⇒ nil
(file-directory-p "$HOME")
⇒ nil
(file-directory-p
(substitute-in-file-name "$HOME"))
⇒ t
若文件 filename 存在且为普通文件(非目录、命名管道、终端或其他 I/O 设备),该函数返回 t;
若文件不存在、非普通文件,或无法确定其是否为普通文件,则返回 nil。
该函数会跟随符号链接。
文件的真实路径(truename)是指:逐层解析所有符号链接直至无链接可解析,再简化路径中出现的 ‘.’ 和 ‘..’ 组件后得到的路径。 这是一种标准化的文件路径形式。一个文件的真实路径不一定唯一——其真实路径的数量等于该文件的硬链接数量。 但真实路径仍十分有用,因为它消除了符号链接导致的路径变体问题。
该函数返回文件 filename 的真实路径。若参数不是绝对路径,函数会先基于 default-directory 展开为绝对路径。
该函数不会展开环境变量,仅 substitute-in-file-name 可实现此功能。See Definition of substitute-in-file-name。
若需要解析 ‘..’ 组件之前的符号链接,调用 file-truename 前请勿直接或间接调用 expand-file-name。
否则 ‘..’ 前的路径组件会在 file-truename 调用前被简化,导致解析不完整。
为避免额外调用 expand-file-name,file-truename 对 ‘~’ 的处理方式与 expand-file-name 一致。
若符号链接的目标采用远程文件路径语法,file-truename 会返回带引号的路径。See Functions that Expand Filenames。
该函数从 filename 开始解析符号链接,直至找到非符号链接的文件名,然后返回该文件名。 该函数不会解析父目录层级的符号链接。
若为 limit 指定数值,则解析完指定数量的链接后,即使结果仍是符号链接,函数也会直接返回当前结果。
为说明 file-chase-links 与 file-truename 的区别,假设 /usr/foo 是指向目录 /home/foo 的符号链接,且 /home/foo/hello 是普通文件(或至少不是符号链接),或不存在。则执行结果如下:
(file-chase-links "/usr/foo/hello")
;; 不解析父目录中的符号链接。
⇒ "/usr/foo/hello"
(file-truename "/usr/foo/hello")
;; 假设 /home 不是符号链接。
⇒ "/home/foo/hello"
若文件 file1 和 file2 指向同一个文件,该函数返回 t。
此功能类似于比较两者的真实路径,但会对远程文件路径进行适配处理。
若 file1 或 file2 不存在,返回值未定义。
有时需要将文件名或其部分作为字符串比较,此时需明确底层文件系统是否区分大小写。
若文件 filename 所在的文件系统不区分大小写,该函数返回 t。
在 MS-DOS 和 MS-Windows 系统上,该函数始终返回 t;
在 Cygwin 和 macOS 系统上,文件系统可能区分或不区分大小写,函数会通过运行时测试判断;若测试结果不确定,Cygwin 下返回 t,macOS 下返回 nil。
目前,除 MS-DOS、MS-Windows、Cygwin 和 macOS 外,该函数在其他平台均返回 nil。
它无法检测挂载文件系统(如 Samba 共享、NFS 挂载的 Windows 卷)的大小写规则;
对于远程主机,‘smb’ 协议默认返回 t,其他协议则通过运行时测试判断。
该函数确定指定文件 file 对应的版本控制(VC)后端。例如,若 emacs.c 受 Git 管理,
(vc-responsible-backend "emacs.c") 会返回 ‘Git’。
注意:若 file 是符号链接,vc-responsible-backend 不会解析它——仅返回符号链接文件自身对应的后端。
若要获取 file 指向的目标文件的 VC 后端,需先用 file-chase-links 等符号链接解析函数处理 file:
(vc-responsible-backend (file-chase-links "emacs.c"))
本节介绍用于获取文件详细信息的函数,包括所有者和组编号、链接数、索引节点(inode)编号、文件大小,以及访问时间和修改时间。
若文件 filename1 比文件 filename2 新,该函数返回 t。
若 filename1 不存在,返回 nil;若 filename1 存在但 filename2 不存在,返回 t;否则比较两个文件的最后修改时间。
以下示例中,假设 aug-19 是 19 号写入的文件,aug-20 是 20 号写入的文件,而 no-file 完全不存在:
(file-newer-than-file-p "aug-19" "aug-20")
⇒ nil
(file-newer-than-file-p "aug-20" "aug-19")
⇒ t
(file-newer-than-file-p "aug-19" "no-file")
⇒ t
(file-newer-than-file-p "no-file" "aug-19")
⇒ nil
若自上次调用该函数以来,文件 filename 的时间戳发生了变化,函数返回非 nil 值。
首次针对某个 filename 调用时,函数会记录文件的最后修改时间和大小;若文件存在,则返回非 nil。
后续针对同一 filename 调用时,会将当前时间戳和大小与记录的值对比,仅当时间戳或大小(或两者)发生变化时,才返回非 nil。
该函数适用于 Lisp 程序需要在文件发生变化时重新读取的场景。
可选参数 tag 必须是符号类型,指定后,仅会对比使用相同 tag 调用时记录的大小和修改时间。
该函数返回文件 filename 的属性列表;若指定文件不存在,返回 nil。
该函数不跟随符号链接。
可选参数 id-format 指定用户 ID(UID)和组 ID(GID)属性的首选格式(见下文)——有效值为 'string(字符串)和 'integer(整数)。后者为默认值,但我们计划修改这一默认设置;因此若你需要使用返回的 UID 或 GID,应显式为 id-format 指定非 nil 的值。
在 GNU 平台上操作本地文件时,该函数是原子操作:若文件系统被其他进程同时修改,函数会返回修改前或修改后的文件属性。
非原子场景下,若检测到竞争条件,函数可能返回 nil,或返回混合了修改前后状态的属性值。
系统提供了访问器函数用于读取该列表中的元素,下文介绍各元素时会同步提及对应的访问器。
属性列表的元素按顺序如下:
t,符号链接返回链接目标字符串,文本文件返回 nil
(访问器:file-attribute-type)。
file-attribute-link-number)。
可通过 add-name-to-file 函数创建备用名称(即硬链接)(see 修改文件名与属性)。
file-attribute-user-id);若未对应命名用户,则返回整数。
file-attribute-group-id)。
file-attribute-access-time)。
时间戳格式与 current-time 一致(see Time of Day),且会截断至文件系统的时间戳精度;例如部分 FAT 格式文件系统仅记录最后访问日期,因此该时间始终为最后访问当天的午夜。
file-attribute-modification-time)。
即文件内容最后被修改的时间。
file-attribute-status-change-time)。
即文件的访问权限位、所有者、所属组,以及文件系统中除内容外其他元信息最后变更的时间。
file-attribute-size)。
file-attribute-modes)。
file-attribute-inode-number)。
file-attribute-device-number)。
后者常用于远程文件,以区分远程文件系统和本地文件系统。
文件的索引节点和设备编号组合可唯一标识系统中的任意文件—不存在两个文件的这两个属性值完全相同。
file-attribute-file-identifier 函数会返回这个唯一标识文件的元组。
例如,以下是文件 files.texi 的属性示例:
(file-attributes "files.texi" 'string)
⇒ (nil 1 "lh" "users"
(20614 64019 50040 152000)
(20000 23 0 0)
(20614 64555 902289 872000)
122295 "-rw-rw-rw-"
t 6473924464520138
1014478468)
该结果的解读如下:
nil既非目录也非符号链接。
1仅有一个名称(即当前默认目录下的 files.texi)。
"lh"所有者为用户 ‘lh’。
"users"所属组为 ‘users’。
(20614 64019 50040 152000)最后访问时间为 2012 年 10 月 23 日 世界协调时间(UTC)20:12:03.050040152。
(若 current-time-list 为 nil,该时间戳等价于 (1351023123050040152 . 1000000000)。)
(20000 23 0 0)最后修改时间为 2001 年 7 月 15 日 世界协调时间(UTC)08:53:43.000000000。
(若 current-time-list 为 nil,该时间戳等价于 (1310720023000000000 . 1000000000)。)
(20614 64555 902289 872000)最后状态变更时间为 2012 年 10 月 23 日 世界协调时间(UTC)20:20:59.902289872。
(若 current-time-list 为 nil,该时间戳等价于 (1351023659902289872 . 1000000000)。)
122295文件大小为 122295 字节。 (但文件中的字符数可能不足 122295——若部分字节属于多字节序列,或行尾格式为回车-换行(CR-LF)。)
"-rw-rw-rw-"权限模式为所有者、所属组、其他用户均拥有读写权限。
t仅为占位值,无实际信息。
6473924464520138索引节点编号为 6473924464520138。
1014478468所在文件系统的设备编号为 1014478468。
该函数返回文件 filename 的链接数(即硬链接数量);若文件不存在,返回 nil。
注意符号链接不影响该函数结果——符号链接不被视为其指向文件的名称。
该函数不跟随符号链接。
$ ls -l foo* -rw-rw-rw- 2 rms rms 4 Aug 19 01:27 foo -rw-rw-rw- 2 rms rms 4 Aug 19 01:27 foo1
(file-nlinks "foo")
⇒ 2
(file-nlinks "doesnt-exist")
⇒ nil
在部分操作系统中,每个文件可以关联任意的文件扩展属性(extended file attributes)。目前 Emacs 支持查询和设置两类特定的文件扩展属性:访问控制列表(ACL)和 SELinux 上下文。在部分系统上,这些扩展属性用于实现比前几节所述的基础 Unix 风格权限更精细的文件访问控制。
关于 ACL 和 SELinux 的详细说明超出了本手册范围。就本节用途而言,每个文件可以关联一个ACL(在基于 ACL 的文件控制系统中描述其权限属性)和/或一个SELinux 上下文(在 SELinux 系统中描述其安全属性)。
该函数返回文件 filename 的 ACL。ACL 在 Lisp 中的具体表示形式未明确指定(未来 Emacs 版本可能发生变化),但其格式与 set-file-acl 接收的 acl 参数一致(see 修改文件名与属性)。
底层 ACL 实现与平台相关:在 GNU/Linux 和 BSD 系统上,Emacs 使用 POSIX ACL 接口;在 MS-Windows 上,Emacs 通过原生文件安全 API 模拟 POSIX ACL 接口。
若系统不支持 ACL 或文件不存在,返回值为 nil。
该函数返回文件 filename 的 SELinux 上下文,格式为列表 (user role type range)。列表元素依次为上下文的用户、角色、类型和范围,均为 Lisp 字符串;具体含义可参考 SELinux 文档。返回值格式与 set-file-selinux-context 接收的 context 参数一致(see 修改文件名与属性)。
若系统不支持 SELinux 或文件不存在,返回值为 (nil nil nil nil)。
该函数返回文件 filename 中 Emacs 可识别的扩展属性关联列表(alist)。目前该函数可一次性获取 ACL 和 SELinux 上下文;之后可调用 set-file-extended-attributes,将返回的关联列表作为第二个参数,把相同的文件访问属性应用到另一个文件(see 修改文件名与属性)。
其中一个元素为 (acl . acl),acl 格式与 file-acl 返回值一致。
另一个元素为 (selinux-context . context),context 为 SELinux 上下文,格式与 file-selinux-context 返回值一致。
本节介绍如何在目录列表(即路径(path))中搜索文件,或在可执行文件标准目录列表中查找可执行文件。
若需查找用户专属配置文件,See 标准文件名 中的 locate-user-emacs-file 函数。
该函数在 path 指定的目录列表中搜索名为 filename 的文件,并依次尝试 suffixes 中的后缀。若找到匹配文件,返回其绝对路径(see 绝对文件名与相对文件名);否则返回 nil。
可选参数 suffixes 给出搜索时追加到 filename 后的文件名后缀列表。locate-file 会对每个目录逐一尝试这些后缀。若 suffixes 为 nil 或 (""),则不使用后缀,直接使用原文件名。常见的 suffixes 取值包括 exec-suffixes(see Functions that Create Subprocesses)、load-suffixes、load-file-rep-suffixes 以及 get-load-suffixes 函数的返回值(see 加载后缀)。
path 的常见取值:查找可执行程序时使用 exec-path(see Functions that Create Subprocesses);查找 Lisp 文件时使用 load-path(see 库搜索)。若 filename 为绝对路径,则 path 无效,但仍会尝试 suffixes 中的后缀。
可选参数 predicate 非空时,指定一个谓词函数用于判断候选文件是否可用。该函数接收候选文件名作为唯一参数。若 predicate 为 nil 或省略,locate-file 使用 file-readable-p 作为默认谓词。其他常用谓词可参考 See 区分文件类型,例如 file-executable-p 和 file-directory-p。
该函数默认跳过目录;若需要查找目录,需让谓词函数对目录返回 dir-ok。示例:
(locate-file "html" '("/var/www" "/srv") nil
(lambda (f) (if (file-directory-p f) 'dir-ok)))
为兼容旧版本,predicate 也可以是符号 executable、readable、writable、exists,或由这些符号组成的列表。
该函数搜索指定程序 program 的可执行文件,返回其绝对路径(包含文件扩展名,如有)。若未找到则返回 nil。函数会在 exec-path 的所有目录中搜索,并尝试 exec-suffixes 中的所有扩展名(see Functions that Create Subprocesses)。
若 remote 非空,且 default-directory 为远程目录,则在对应远程主机上搜索 program。
本节中的函数用于对文件进行重命名、复制、删除、创建链接,以及设置
文件模式(权限)。通常情况下,若这些函数执行失败,会触发
file-error 错误,并报告与系统相关、描述失败原因的错误信息。
若因文件不存在而失败,则会触发 file-missing 错误。
出于性能考虑,操作系统可能会对这些函数所做的修改进行缓存或别名处理, 而不会立即写入二级存储。See 文件与辅助存储。
在带有参数 newname 的函数中,如果该参数是一个目录名, 会被视为已自动拼接上原文件名中非目录的部分。通常,目录名是以 ‘/’ 结尾的名称(see 目录名)。例如,若原文件名为 a/b/c,则 newname 为 d/e/f/ 时,会被当作 d/e/f/c 处理。若 newname 并非显式目录名, 但指向的文件实际是目录,则不适用该特殊处理; 例如,即使 d/e/f 恰好是目录,newname 仍保持为 d/e/f。
在带有参数 newname 的函数中,若名为 newname 的文件已存在, 具体行为由参数 ok-if-already-exists 的值决定:
nil,
触发 file-already-exists 错误。
该函数为名为 oldname 的文件添加额外名称 newname。 这意味着 newname 会成为指向 oldname 的新硬链接。
若 newname 是符号链接,则替换其自身的目录项, 而非它所指向的目录项。若 oldname 是符号链接, 该函数可能会也可能不会解析该链接;在 GNU 平台上不会解析链接。 若 oldname 是目录,该函数通常会执行失败, 尽管在少数老式非 GNU 平台上,超级用户可以执行成功, 并创建出非树形结构的文件系统。
在下面示例的第一部分,我们列出两个文件:foo 和 foo3。
$ ls -li fo* 81908 -rw-rw-rw- 1 rms rms 29 Aug 18 20:32 foo 84302 -rw-rw-rw- 1 rms rms 24 Aug 18 20:31 foo3
接下来调用 add-name-to-file 创建硬链接,然后再次列出文件。
可以看到同一个文件拥有两个名称:foo 和 foo2。
(add-name-to-file "foo" "foo2")
⇒ nil
$ ls -li fo* 81908 -rw-rw-rw- 2 rms rms 29 Aug 18 20:32 foo 81908 -rw-rw-rw- 2 rms rms 29 Aug 18 20:32 foo2 84302 -rw-rw-rw- 1 rms rms 24 Aug 18 20:31 foo3
最后,执行如下代码:
(add-name-to-file "foo" "foo3" t)
并再次列出文件。此时同一个文件拥有三个名称: foo、foo2 和 foo3。foo3 原先的内容会丢失。
(add-name-to-file "foo1" "foo3")
⇒ nil
$ ls -li fo* 81908 -rw-rw-rw- 3 rms rms 29 Aug 18 20:32 foo 81908 -rw-rw-rw- 3 rms rms 29 Aug 18 20:32 foo2 81908 -rw-rw-rw- 3 rms rms 29 Aug 18 20:32 foo3
在不允许单个文件拥有多个名称的操作系统上,该函数无实际意义。 部分系统会通过复制文件来实现“多名称”效果。
另请参见 文件属性 中的 file-nlinks。
该命令将文件 filename 重命名为 newname。
若 filename 除自身外还有其他名称,这些名称会继续保留。
实际上,先用 add-name-to-file 添加名称 newname,
再删除 filename,其效果与重命名基本一致,
仅在瞬时中间状态、错误处理、目录与符号链接处理上存在差异。
该命令不会解析符号链接。若 filename 是符号链接, 命令重命名的是符号链接本身,而非其指向的文件。 若 newname 是符号链接,则替换其自身的目录项, 而非它所指向的目录项。
若 filename 与 newname 指向同一个目录项, 即二者父目录相同且内部文件名一致,则该命令不执行任何操作。 否则,若二者指向同一个文件,在符合 POSIX 标准的系统上不执行操作, 在部分非 POSIX 系统上则会删除 filename。
如果 newname 已存在,那么当 oldname 是目录时, newname 必须是空目录;其他情况下 newname 必须是非目录文件。
该命令将文件 oldname 复制到 newname。 若 oldname 不是普通文件,会触发错误。 若 newname 指向一个目录,则会将 oldname 复制到该目录下, 并保留原文件名。
该函数会解析符号链接,但不会解析悬空符号链接来创建 newname。
若 time 非 nil,该函数会为新文件设置与原文件相同的最后修改时间。
(仅部分操作系统支持。)若设置时间时出错,
copy-file 会触发 file-date-error 错误。
在交互式调用中,前缀参数会为 time 指定非 nil 值。
若参数 preserve-uid-gid 为 nil,
由操作系统决定新文件的用户与用户组归属(通常设为运行 Emacs 的用户)。
若 preserve-uid-gid 非 nil,
会尝试复制原文件的用户与用户组归属。
该操作仅在部分系统上有效,且需要具备相应权限。
若可选参数 preserve-permissions 非 nil,
该函数会将 oldname 的文件模式(即 “权限(permissions)”)、
访问控制列表(ACL)与 SELinux 上下文(如有)一并复制到 newname。
See 文件信息。
否则,若 newname 为已存在文件,其文件模式保持不变;
若为新建文件,则继承 oldname 的模式并与默认文件权限掩码叠加
(见下方 set-default-file-modes)。
两种情况下均不会复制访问控制列表或 SELinux 上下文。
该命令创建一个指向 target 的符号链接,名称为 linkname。其效果与 Shell 命令 ‘ln -s target linkname’ 一致。参数 target 仅被当作字符串处理,无需指向已存在的文件。 若 ok-if-already-exists 为整数(表示交互式调用), 则会对 target 字符串中开头的 ‘~’ 进行展开, 并去除开头的 ‘/:’。
若 target 为相对文件名,生成的符号链接将 相对于该符号链接所在目录进行解析。 See 绝对文件名与相对文件名。
若 target 与 linkname 均采用远程文件名称语法, 且二者的远程标识相同,则该符号链接指向 target 的本地文件名部分。
本函数在不支持符号链接的系统上不可用。
该命令删除文件 filename。若该文件存在多个名称,
则其在其他名称下依然存在。若 filename
为符号链接,delete-file 仅删除链接本身,
而非其指向的目标文件。
若无法删除 filename,该命令会触发对应类型的
file-error 错误。(在 GNU 及类 POSIX 系统上,
只要文件所在目录可写,即可删除该文件。)
若文件不存在,该命令不会触发任何错误。
若可选参数 trash 非 nil,
且变量 delete-by-moving-to-trash 非 nil,
则该命令会将文件移入系统回收站而非直接删除。
See Miscellaneous File Operations in The GNU
Emacs Manual。交互式调用时,若未给出前缀参数,
trash 为 t,否则为 nil。
另请参见 创建、复制和删除目录 中的 delete-directory。
若该变量非 nil,远程文件将不会被移入回收站,
而是直接删除。
该函数将 filename 的文件模式(file mode)(即权限(permissions)) 设置为 mode。
默认情况下该函数会跟随符号链接。但若可选参数 flag
为符号 nofollow,则当 filename 是符号链接时
不会对其进行解析;这可避免意外修改其他位置文件的权限位。
在不支持修改符号链接权限位的平台上,若 filename
为符号链接且 flag 为 nofollow,该函数会触发错误。
非交互式调用时,mode 必须为整数。 仅使用该整数的低 12 位;在大多数系统上, 仅低 9 位有效。可使用 Lisp 的八进制数格式输入 mode。 例如:
(set-file-modes "myfile" #o644 'nofollow)
表示该文件对所有者可读可写,
对组成员可读,对其他所有用户可读。
See File permissions in The GNU Coreutils Manual
可查看权限位的说明。
交互式调用时,mode 通过 read-file-modes
(见下文)从迷你缓冲区读取,用户可输入整数,
也可输入符号化的权限字符串。
另请参见 测试文件可访问性 中的函数 file-modes,
该函数用于获取文件的权限。
该函数设置 Emacs 及其子进程创建新文件时的默认权限。
Emacs 创建的所有文件初始均具有这些权限(或其子集;
即使默认文件权限允许执行,write-region 也不会授予执行权限)。
在 GNU 及类 POSIX 系统上,默认权限由 ‘umask’ 值
按位取反得到,即:参数 mode 中被置位的位,
会在 Emacs 创建文件时使用的默认权限中被清除。
参数 mode 应为表示权限的整数,
用法与上述 set-file-modes 类似。
仅低 9 位有效。
保存已存在文件的修改版本时,默认文件权限不生效; 保存文件会保留其原有权限。
该宏在执行 body 中的表达式时,
临时将新文件的默认权限设置为 mode(取值规则同
set-file-modes)。执行完毕后恢复原有默认权限,
并返回 body 中最后一个表达式的值。
例如可用于创建私有文件。
该函数以整数形式返回当前默认文件权限。
该函数从迷你缓冲区读取一组文件权限位。 第一个可选参数 prompt 用于指定非默认提示文本。 第二个可选参数 base-file 为一个文件名, 若用户输入的权限位是相对于某现有文件的权限, 则以此文件的权限为基准计算返回值。
若用户输入为八进制数,该函数直接返回该数值。
若为完整的符号化权限描述(如 "u=rwx"),
函数通过 file-modes-symbolic-to-number
将其转换为等效数值并返回。若为相对描述(如 "o+g"),
则基准权限取自 base-file 的权限位。
若 base-file 省略或为 nil,
则使用 0 作为基准权限位。
完整描述与相对描述可混用,例如 "u+r,g+rx,o+r,g-w"。
See File permissions in The GNU Coreutils Manual
可查看文件权限格式说明。
该函数将 modes 中的符号化文件权限描述
转换为等效整数。若符号化描述基于现有文件,
则该文件的权限位由可选参数 base-modes 提供;
若该参数省略或为 nil,默认值为 0,
即无任何访问权限。
该函数将 modes 中的数值型文件权限
转换为等效字符串形式。返回的字符串格式
与 Shell 命令 ls -l 及 file-attributes
的输出一致,不等同于 file-modes-symbolic-to-number
与 Shell 命令 chmod 所接受的符号格式。
该函数将 filename 的访问时间与修改时间
设置为 time。设置成功返回 t,
否则返回 nil。time 默认为当前时间,
且必须为合法时间值(see Time of Day)。
默认情况下该函数会跟随符号链接。但若可选参数 flag
为符号 nofollow,则当 filename 是符号链接时
不会对其进行解析;这可避免意外修改其他位置文件的时间。
在不支持修改符号链接时间的平台上,若 filename
为符号链接且 flag 为 nofollow,该函数会触发错误。
该函数为 filename 设置 Emacs 可识别的扩展文件属性。
第二个参数 attribute-alist 应为与
file-extended-attributes 返回格式相同的关联列表。
属性设置成功返回 t,否则返回 nil。
See 文件扩展属性。
该函数将 filename 的 SELinux 安全上下文
设置为 context。参数 context
应为列表 (user role type range),
其中每个元素均为字符串。See 文件扩展属性。
函数成功设置 SELinux 上下文时返回 t。
若未设置成功(例如 SELinux 被禁用,
或编译 Emacs 时未启用 SELinux 支持)则返回 nil。
该函数将 filename 的访问控制列表(ACL)
设置为 acl。参数 acl 的格式
应与函数 file-acl 的返回值一致。
See 文件扩展属性。
函数成功设置 ACL 时返回 t,否则返回 nil。
Emacs 修改文件后,修改内容可能无法在后续断电或存储介质故障中保留, 原因有二,均与效率相关。其一,操作系统可能将写入的数据与 已存储在辅助存储其他位置的数据做别名映射,直到其中一个文件被后续修改; 若辅助存储上的唯一副本因介质故障丢失,两个文件都会损坏。 其二,操作系统可能不会立即将数据写入辅助存储, 若此时断电或发生介质故障,数据将会丢失。
尽管通过适当配置的系统可以在很大程度上避免这两类故障,
但这类系统通常成本更高或效率更低。在低端系统中,
要在介质故障后保留数据,可将文件复制到不同设备;
要在断电后保留数据(或立即获知介质故障),
可使用 write-region 函数,并将变量
write-region-inhibit-fsync 设置为 nil。
该变量通常为 t,因为这能显著提升性能;
但如果在低端系统上使用 Emacs 实现可抵御断电的类数据库事务,
将其临时绑定为 nil 会更合理。
See 写入文件。
在部分平台上,Emacs 修改文件后,其他进程可能不会立即收到变更通知。
将 write-region-inhibit-fsync 设为 nil
可能会加快此类通知,但不提供保证。
与其他程序一样,Emacs 中通常通过文件名引用文件。 Emacs 中的文件名以字符串形式表示。 所有操作文件的函数均要求传入文件名参数。
除了直接操作文件本身,Emacs Lisp 程序还经常需要处理文件名, 即拆分文件名,并使用名称的一部分构造相关文件名。 本节介绍如何操作文件名。
本节中的函数并不会实际访问文件, 因此可以处理那些不指向现有文件或目录的文件名。
在 MS-DOS 和 MS-Windows 上,这些函数(与实际操作文件的函数一样) 既接受以反斜杠分隔路径组件的 MS-DOS 或 MS-Windows 文件名语法, 也接受 POSIX 语法;但它们始终返回 POSIX 格式。 这使得 Lisp 程序可以使用 POSIX 语法指定文件名, 并在所有系统上无需修改即可正常运行。20
操作系统将文件分组存放于目录中。 要指定一个文件,必须同时指定目录及其在该目录下的文件名。 因此,Emacs 将文件名视为由两大部分组成: 目录名(directory name)部分与非目录(nondirectory)部分(即目录内文件名(file name within the directory))。 两部分均可为空。将两部分拼接即可还原原始文件名。 21
在大多数系统上,目录部分包含直至最后一个斜杠的所有内容 (MS-DOS 或 MS-Windows 输入中也允许使用反斜杠); 非目录部分为剩余内容。
在某些用途下,非目录部分会进一步拆分为主体名称与 版本号(version number)。在大多数系统上,只有备份文件的名称中包含版本号。
该函数返回 filename 的目录部分,格式为目录名(see 目录名);
若 filename 不包含目录部分,则返回 nil。
在 GNU 及类 POSIX 系统上,该函数返回的字符串总是以斜杠结尾。 在 MS-DOS 上也可能以冒号结尾。
(file-name-directory "lewis/foo") ; GNU example
⇒ "lewis/"
(file-name-directory "foo") ; GNU example
⇒ nil
该函数返回 filename 的非目录部分。
(file-name-nondirectory "lewis/foo")
⇒ "foo"
(file-name-nondirectory "foo")
⇒ "foo"
(file-name-nondirectory "lewis/")
⇒ ""
该函数返回去除了文件版本号、备份版本号或末尾波浪号后的 filename。
若 keep-backup-version 非 nil,
则返回值会丢弃文件系统识别的真实版本号,但保留备份版本号。
(file-name-sans-versions "~rms/foo.~1~")
⇒ "~rms/foo"
(file-name-sans-versions "~rms/foo~")
⇒ "~rms/foo"
(file-name-sans-versions "~rms/foo")
⇒ "~rms/foo"
该函数在对 filename 应用 file-name-sans-versions
去除版本/备份部分后,返回其最终扩展名(若有)。
文件名中的扩展名,是指最后一个名称组件中最后一个
‘.’ 之后的部分(已去除版本/备份部分)。
对于无扩展名的文件名(如 foo),该函数返回 nil。
对于空扩展名(如 foo.),返回 ""。
若文件名最后一个组件以 ‘.’ 开头,
该 ‘.’ 不计为扩展名起始。
因此,.emacs 的扩展名为 nil,而非 ‘.emacs’。
若 period 非 nil,
返回值会包含分隔扩展名的点;
若 filename 无扩展名,则值为 ""。
该函数返回将扩展名设置为 extension 后的 filename。 extension 中开头的单个点会被自动去除。例如:
(file-name-with-extension "file" "el")
⇒ "file.el"
(file-name-with-extension "file" ".el")
⇒ "file.el"
(file-name-with-extension "file.c" "el")
⇒ "file.el"
注意:若 filename 或 extension 为空,
或 filename 格式为目录(即 directory-name-p 返回非 nil),
该函数会报错。
该函数返回去除扩展名后的 filename(若有扩展名)。 若存在版本/备份部分,仅当文件有扩展名时才会将其移除。例如:
(file-name-sans-extension "foo.lose.c")
⇒ "foo.lose"
(file-name-sans-extension "big.hack/foo")
⇒ "big.hack/foo"
(file-name-sans-extension "/my/home/.emacs")
⇒ "/my/home/.emacs"
(file-name-sans-extension "/my/home/.emacs.el")
⇒ "/my/home/.emacs"
(file-name-sans-extension "~/foo.el.~3~")
⇒ "~/foo"
(file-name-sans-extension "~/foo.~3~")
⇒ "~/foo.~3~"
注意最后两个例子中的 ‘.~3~’ 是备份部分,并非扩展名。
该函数等价于依次调用 file-name-sans-extension
与 file-name-nondirectory。例如:
(file-name-base "/my/home/foo.c")
⇒ "foo"
该函数将文件名拆分为组件列表,
可视为使用对应目录分隔符调用 string-join 的逆操作。例如:
(file-name-split "/tmp/foo.txt")
⇒ ("" "tmp" "foo.txt")
(string-join (file-name-split "/tmp/foo.txt") "/")
⇒ "/tmp/foo.txt"
文件系统中的所有目录构成一棵从根目录开始的目录树。 文件名可以从树的根节点开始指定全部目录名称, 这样的名称称为绝对(absolute)文件名。 文件名也可以指定文件相对于某个默认目录在目录树中的位置, 这样的名称称为相对(relative)文件名。
在 GNU 及类 POSIX 系统上,在对开头的 ‘~’ 完成展开后, 绝对文件名以 ‘/’ 开头(see abbreviate-file-name), 而相对文件名则不是。 在 MS-DOS 和 MS-Windows 上,绝对文件名以斜杠或反斜杠开头, 或以驱动器格式 ‘x:/’ 开头,其中 x 为驱动器号(drive letter)。
若文件名 filename 为绝对文件名,该函数返回 t,
否则返回 nil。
满足以下条件的文件名会被视为绝对文件名:
其第一个组件为 ‘~’,
或为 ‘~user’ 且 user 为有效登录用户名。
以下示例假设存在用户 ‘rms’,但不存在用户 ‘nosuchuser’。
(file-name-absolute-p "~rms/foo")
⇒ t
(file-name-absolute-p "~nosuchuser/foo")
⇒ nil
(file-name-absolute-p "rms/foo")
⇒ nil
(file-name-absolute-p "/user/rms/foo")
⇒ t
对于一个可能为相对路径的文件名,
你可以使用 expand-file-name 展开开头的 ‘~’
并将结果转为绝对文件名(see 文件名展开相关函数)。
下面这个函数则用于将绝对文件名转为相对文件名:
该函数尝试返回一个与 filename 等价的相对名称,
假定该结果将相对于 directory(一个绝对目录名或目录文件名)进行解析。
若 directory 省略或为 nil,则默认为当前缓冲区的默认目录。
在部分操作系统中,绝对文件名以设备名开头。
在这类系统上,如果 filename 与 directory
以不同设备名开头,则不存在基于 directory 的等价相对路径,
此时 file-relative-name 会直接返回绝对形式的 filename。
(file-relative-name "/foo/bar" "/foo/")
⇒ "bar"
(file-relative-name "/foo/bar" "/hack/")
⇒ "../foo/bar"
空字符串形式的文件名代表当前缓冲区的默认目录。
目录名(directory name)是一个字符串,只要它指向某个文件,就必须指向一个目录。 目录本质上也是一种文件,它拥有一个文件名(称为目录文件名称(directory file name)), 该名称与目录名相关,但通常并不完全相同。 (这与通常的 POSIX 术语略有区别。) 同一实体的这两种名称通过语法转换相互关联。
在 GNU 及类 POSIX 系统上,转换规则很简单: 对一个尚未以 ‘/’ 结尾的目录文件名,在末尾添加 ‘/’ 即可得到目录名。 在 MS-DOS 上,二者关系更为复杂。
目录名与目录文件名称之间的区别细微但至关重要。
当某个 Emacs 变量或函数参数被说明为目录名时,
传入目录文件名称是不被接受的。
file-name-directory 返回的字符串始终是目录名。
下面两个函数用于在目录名与目录文件名称之间转换。 它们不会对环境变量替换(如 ‘$HOME’) 以及 ‘~’、‘.’、‘..’ 等结构做特殊处理。
该函数返回一个字符串, 表示操作系统会将 filename 解析为目录的形式(即目录名)。 在大多数系统上,这意味着在字符串末尾添加斜杠(如果原本没有)。
(file-name-as-directory "~rms/lewis")
⇒ "~rms/lewis/"
若 filename 以目录分隔符结尾,该函数返回非 nil。
在 GNU 及类 POSIX 系统上目录分隔符为正斜杠 ‘/’;
MS-Windows 与 MS-DOS 同时识别正斜杠与反斜杠 ‘\’ 作为目录分隔符。
该函数返回一个字符串, 表示操作系统会将 dirname 解析为普通文件的形式(即目录文件名称)。 在大多数系统上,这意味着移除字符串末尾的目录分隔符, 除非该字符串完全由目录分隔符组成。
(directory-file-name "~lewis/")
⇒ "~lewis"
将 components 拼接至 directory 之后, 若 directory 或前一个组件未以斜杠结尾, 则在组件前自动插入斜杠。
(file-name-concat "/tmp" "foo")
⇒ "/tmp/foo"
值为 nil 或空字符串的 directory 或组件会被忽略——
它们会被优先过滤,且不会对结果产生任何影响。
该函数与直接使用 concat 效果几乎一致,
区别在于 dirname(以及非末尾组件)无论是否以斜杠结尾,
本函数都不会产生重复斜杠。
大多数场景下,使用一次或多次 expand-file-name
(see 文件名展开相关函数)生成带前置目录的文件名,
会比本函数更合适。
仅当 expand-file-name 的某些特殊处理与程序需求冲突时,
才使用本函数。
例如,expand-file-name 对 ~、~user、
nil 的特殊处理,或是对 . 和 .. 的移除,
可能并非你所期望的行为。
如需将目录名转换为缩写形式,可使用以下函数:
该函数返回 filename 的缩写形式。
它会先应用 directory-abbrev-alist 中指定的缩写规则
(see File Aliases in The GNU Emacs Manual),
若参数指向用户主目录或其子目录下的文件,
再用 ‘~’ 替换主目录路径。
若主目录本身为根目录,则不会替换为 ‘~’,
因为在多数系统上这并不会缩短路径。
该函数既可用于目录名,也可用于普通文件名, 因为它能识别名称中任意位置的缩写。
该函数返回 filename 所在父目录的目录名。
若 filename 位于文件系统根目录,则返回 nil。
若 filename 为相对路径,则假定其相对于 default-directory,
此时返回值也为相对路径。
若返回值非 nil,则一定以斜杠结尾。
对文件名进行展开(expanding),是指将相对文件名转换为绝对文件名。 由于这一过程是相对于某个默认目录完成的, 你必须同时指定默认目录与待展开的文件名。 展开还包括对 ~/ 这类缩写的解析 (see abbreviate-file-name), 以及消除 ./ 和 name/../ 这类冗余路径。
该函数将 filename 转换为绝对文件名。
若提供了 directory,则当 filename 为相对路径且不以 ‘~’ 开头时,
以此作为起始默认目录。
(directory 本身应为绝对目录名或目录文件名;可以 ‘~’ 开头。)
否则使用当前缓冲区的 default-directory。例如:
(expand-file-name "foo")
⇒ "/xcssun/users/rms/lewis/foo"
(expand-file-name "../foo")
⇒ "/xcssun/users/rms/foo"
(expand-file-name "foo" "/usr/spool/")
⇒ "/usr/spool/foo"
若 filename 中第一个斜杠前的部分为 ‘~’,
会被展开为你的主目录,通常由环境变量 HOME 指定
(see General Variables in The GNU Emacs Manual)。
若第一个斜杠前为 ‘~user’ 且 user 为有效登录名,
则展开为该用户的主目录。
如果你不希望对可能以字面量 ‘~’ 开头的相对文件名进行展开,
可以使用 (concat (file-name-as-directory directory) filename)
代替 (expand-file-name filename directory)。
包含 ‘.’ 或 ‘..’ 的文件名会被简化为规范形式:
(expand-file-name "bar/../foo")
⇒ "/xcssun/users/rms/lewis/foo"
某些情况下,开头的 ‘..’ 组件可能会保留在结果中:
(expand-file-name "../home" "/")
⇒ "/../home"
这是为了兼容那些在根目录 / 之上还有超级根概念的文件系统。 在其他文件系统中,/../ 与 / 解析效果完全一致。
展开 . 或空字符串会返回默认目录:
(expand-file-name "." "/usr/spool/")
⇒ "/usr/spool"
(expand-file-name "" "/usr/spool/")
⇒ "/usr/spool"
注意:expand-file-name 不会 展开环境变量,
只有 substitute-in-file-name 会执行该操作:
(expand-file-name "$HOME/foo")
⇒ "/xcssun/users/rms/lewis/$HOME/foo"
另外,expand-file-name 在任何层级都不会跟随符号链接。
这导致 file-truename 与 expand-file-name
对 ‘..’ 的处理方式存在差异。
假设 ‘/tmp/bar’ 是指向目录 ‘/tmp/foo/bar’ 的符号链接,则结果如下:
(file-truename "/tmp/bar/../myfile")
⇒ "/tmp/foo/myfile"
(expand-file-name "/tmp/bar/../myfile")
⇒ "/tmp/myfile"
如果你需要在 ‘..’ 之前跟随符号链接,
应确保直接调用 file-truename,
而不事先直接或间接调用 expand-file-name。See 真实路径。
这个缓冲区局部变量的值为当前缓冲区的默认目录。 它应为绝对目录名,可以 ‘~’ 开头。 该变量在每个缓冲区中都是局部有效的。
当 expand-file-name 的第二个参数为 nil 时,
会使用该默认目录。
其值始终是以斜杠结尾的字符串。
default-directory
⇒ "/user/lewis/manual/"
该函数将 filename 中的环境变量引用替换为对应变量值。 遵循标准 Unix Shell 语法,‘$’ 为环境变量替换前缀。 若输入中包含 ‘$$’,会被转换为 ‘$’, 用户可通过这种方式对 ‘$’ 进行转义。
环境变量名是 ‘$’ 之后的一串字母、数字(包含下划线)。 若 ‘$’ 后紧跟 ‘{’, 则变量名为从该位置到匹配的 ‘}’ 之间的内容。
对已经经过 substitute-in-file-name 处理的结果
再次调用该函数,通常会产生错误。
例如,用于转义的 ‘$$’ 无法正常工作,
且环境变量值中的 ‘$’ 可能引发重复替换。
因此,若程序调用该函数后,输出会再次被传入本函数,
需要将所有 ‘$’ 加倍,以避免后续错误。
这里假设保存用户主目录的环境变量 HOME
值为 ‘/xcssun/users/rms’。
(substitute-in-file-name "$HOME/foo")
⇒ "/xcssun/users/rms/foo"
替换完成后,若 ‘~’ 或 ‘/’ 紧跟在另一个 ‘/’ 之后, 函数会丢弃其之前的所有内容(直到紧邻的前一个 ‘/’)。
(substitute-in-file-name "bar/~/foo")
⇒ "~/foo"
(substitute-in-file-name "/usr/local/$HOME/foo")
⇒ "/xcssun/users/rms/foo"
;; /usr/local/ has been discarded.
某些场景下并不希望展开文件名。 此时可以对文件名进行引用,阻止展开并按字面量处理。 引用方式为在文件名前添加前缀 ‘/:’。
该宏为文件名 name 添加引用前缀 ‘/:’。 对于本地文件名 name,直接在前方添加 ‘/:’。 若 name 为远程文件名,则对其本地部分(see 实现“魔法”文件名机制)进行引用。 若 name 已是被引用的文件名,则直接原样返回。
(substitute-in-file-name (file-name-quote "bar/~/foo"))
⇒ "/:bar/~/foo"
(substitute-in-file-name (file-name-quote "/ssh:host:bar/~/foo"))
⇒ "/ssh:host:/:bar/~/foo"
该宏无法用于阻止魔法文件名的文件名处理器生效(see 实现“魔法”文件名机制)。
该宏从文件名 name 中移除引用前缀 ‘/:’(如果存在)。 若 name 为远程文件名,则对其本地部分取消引用。
若 name 带有前缀 ‘/:’ 被引用,该宏返回非 nil。
若 name 为远程文件名,则检查其本地部分。
有些程序需要写入临时文件。为这类文件构造名称的常用方式如下:
(make-temp-file name-of-application)
make-temp-file 的作用是避免两个不同用户或两个不同任务试图使用完全相同的文件名。
该函数创建一个临时文件并返回其名称。Emacs 会在 prefix 后追加若干随机字符生成临时文件名,每次运行 Emacs 时生成的字符都不同。返回的名称一定对应一个新建文件;如果以字符串形式提供了 text,文件会包含该内容,否则为空。在 MS-DOS 上,该函数可能会截断 prefix 以适应 8+3 文件名限制。如果 prefix 是相对文件名,会基于 temporary-file-directory 进行展开。
(make-temp-file "foo")
⇒ "/tmp/foo232J6v"
make-temp-file 返回时,文件已经创建且为空。此时你应当向文件中写入预期内容。
如果 dir-flag 非 nil,make-temp-file 会创建一个空目录而非空文件。它返回的是该目录的文件名,而非目录名。See 目录名。
如果 suffix 非 nil,make-temp-file 会将其追加到文件名末尾。
如果 text 是字符串,make-temp-file 会将其插入文件中。
为避免同一 Emacs 中不同库之间产生冲突,每个使用 make-temp-file 的 Lisp 程序都应使用自己的 prefix。追加在 prefix 后的数字用于区分在不同 Emacs 进程中运行的同一应用。额外追加的字符可保证在单个 Emacs 进程内也能生成大量不同名称。
临时文件的默认目录由变量 temporary-file-directory 控制。该变量为用户提供了统一指定所有临时文件目录的方式。部分程序在 small-temporary-file-directory 非 nil 时会改用该目录。使用时应在调用 make-temp-file 之前,先将前缀在对应目录下展开。
该变量指定用于创建临时文件的目录名。其值应为目录名(see 目录名),但 Lisp 程序最好能兼容传入目录文件名的情况。将其作为 expand-file-name 的第二个参数是实现这一点的好方法。
默认值根据操作系统合理设定;它基于 TMPDIR、TMP 和 TEMP 环境变量,如果这些变量均未定义,则回退到系统默认目录名。
即使你不使用 make-temp-file 创建临时文件,也应使用该变量决定将文件放在哪个目录下。不过,如果你预计文件会很小,应优先使用非 nil 的 small-temporary-file-directory。
该变量指定用于创建某些大概率体积较小的临时文件的目录名。
如果你要写入一个大概率很小的临时文件,应按如下方式确定目录:
(make-temp-file
(expand-file-name prefix
(or small-temporary-file-directory
temporary-file-directory)))
该函数生成一个可能唯一的文件名字符串。名称以 base-name 开头,并追加若干随机字符,每次 Emacs 运行时都不同。它与 make-temp-file 类似,区别在于:(i) 它只构造名称而不创建文件;(ii) base-name 应为非魔法格式的绝对文件名;(iii) 如果返回的文件名是魔法格式,它可能指向一个已存在的文件。See 实现“魔法”文件名机制。
警告:大多数情况下不应使用该函数,而应使用 make-temp-file!该函数存在竞态条件问题,即在 make-temp-name 调用与文件创建之间可能被利用,在某些场景下会引发安全漏洞。
有时需要在远程主机或挂载目录上创建临时文件。下面两个函数支持这一场景。
该函数与 make-temp-file 类似,但会尽可能在靠近 default-directory 的位置创建临时文件。如果 prefix 是相对文件名,且 default-directory 是远程文件名或位于挂载文件系统上,则临时文件会创建在函数 temporary-file-directory 返回的目录中。否则直接使用 make-temp-file。prefix、dir-flag 和 suffix 的含义与 make-temp-file 中一致。
(let ((default-directory "/ssh:remotehost:"))
(make-nearby-temp-file "foo"))
⇒ "/ssh:remotehost:/tmp/foo232J6v"
通过 make-nearby-temp-file 写入临时文件所用的目录。如果 default-directory 是远程路径,则返回对应远程主机上的临时文件目录。如果该目录不存在,或 default-directory 位于挂载文件系统(参见 mounted-file-systems),则函数返回 default-directory。对于非远程、非挂载的 default-directory,返回变量 temporary-file-directory 的值。
要提取临时文件名的本地部分,可使用 file-local-name(see 实现“魔法”文件名机制)。
本节描述用于文件名补全的底层子程序。更高阶的函数请参见 读取文件名。
该函数返回目录 directory 中所有以 partial-filename 开头的文件的完整补全列表。补全项的顺序与目录中文件的顺序一致,该顺序不可预测且不携带有效信息。
参数 partial-filename 必须是不包含目录部分、不含斜杠(部分系统中为反斜杠)的文件名。如果 directory 不是绝对路径,会在前面拼接当前缓冲区的默认目录。
下面的例子假设当前默认目录为 ~rms/lewis,其中有 5 个文件名以 ‘f’ 开头:foo、file~、file.c、file.c.~1~ 和 file.c.~2~。
(file-name-all-completions "f" "")
⇒ ("foo" "file~" "file.c.~2~"
"file.c.~1~" "file.c")
(file-name-all-completions "fo" "")
⇒ ("foo")
该函数在目录 directory 中对文件名 filename 进行补全,返回所有以 filename 开头的文件名的最长公共前缀。如果 predicate 非 nil,则会忽略不满足该谓词的补全项;调用该谓词时会传入一个参数,即展开后的绝对文件名。
如果只有一个匹配项且 filename 与其完全一致,函数返回 t。如果目录 directory 中没有以 filename 开头的名称,则返回 nil。
下面的例子假设当前默认目录中有 5 个文件名以 ‘f’ 开头:foo、file~、file.c、file.c.~1~ 和 file.c.~2~。
(file-name-completion "fi" "")
⇒ "file"
(file-name-completion "file.c.~1" "")
⇒ "file.c.~1~"
(file-name-completion "file.c.~1~" "")
⇒ t
(file-name-completion "file.c.~3" "")
⇒ nil
file-name-completion 通常会忽略以此列表中任意字符串结尾的文件名。当所有可能补全都以这些后缀之一结尾时,则不会忽略。该变量对 file-name-all-completions 无影响。
一个典型取值如下:
completion-ignored-extensions
⇒ (".o" ".elc" "~" ".dvi")
如果 completion-ignored-extensions 中的元素以斜杠 ‘/’ 结尾,表示匹配目录。不以斜杠结尾的元素不会匹配目录;因此上面的值不会过滤掉名为 foo.elc 的目录。
有时,Emacs Lisp 程序需要为特定用途指定一个标准文件名——通常用于存放当前用户的配置数据。这类文件一般应放在 user-emacs-directory 指定的目录下,默认通常为 ~/.config/emacs/ 或 ~/.emacs.d/(see How Emacs Finds Your Init File in The GNU Emacs Manual)。例如,缩写定义默认保存在 ~/.config/emacs/abbrev_defs 或 ~/.emacs.d/abbrev_defs。指定这类文件名最简单的方式是使用函数 locate-user-emacs-file。
该函数返回一个 Emacs 专用配置或数据文件的绝对文件名。参数 base-name 应为相对文件名。返回值是 user-emacs-directory 目录下对应文件的绝对路径;如果该目录不存在,函数会创建它。
如果可选参数 old-name 非 nil,它指定用户主目录下的文件 ~/old-name。如果该文件存在,则返回该文件的绝对路径,而非 base-name 指定的文件。该参数用于 Emacs 包提供向后兼容。例如,在引入 user-emacs-directory 之前,缩写文件位于 ~/.abbrev_defs。下面是 abbrev-file-name 的定义:
(defcustom abbrev-file-name (locate-user-emacs-file "abbrev_defs" ".abbrev_defs") "Default name of file from which to read abbrevs." ... :type 'file)
一个用于标准化文件名的更低层函数是 convert-standard-filename,它被 locate-user-emacs-file 作为子程序使用。
该函数基于 filename 返回一个符合当前操作系统规范的文件名。
在 GNU 及类 POSIX 系统上,它直接返回 filename。在其他操作系统上,它会强制执行系统特定的文件名规范;例如在 MS-DOS 上,该函数会做一系列修改以满足 8.3 格式限制,包括将开头的 ‘.’ 转为 ‘_’,并将点号后的字符截断为 3 个。
推荐用法是:先指定一个符合 GNU/Unix 规范的名称,再传入 convert-standard-filename。
目录是一种特殊文件,其中包含以不同名称登记的其他文件。目录是文件系统的一项功能。
Emacs 可以将目录中的文件名以 Lisp 列表形式返回,也可以使用 Shell 命令 ls 在缓冲区中显示这些名称。在后一种情况下,可以根据传给 ls 的选项可选地显示每个文件的相关信息。
该函数返回目录 directory 中的文件名列表。默认按字母顺序排序。
如果 full-name 非 nil,函数返回文件的绝对文件名;否则返回相对于指定目录的文件名。
如果 match-regexp 非 nil,函数只返回非目录部分匹配该正则表达式的文件名,其他文件名将被排除。在大小写不敏感的文件系统上,正则匹配也不区分大小写。
如果 nosort 非 nil,directory-files 不会对列表排序,返回的文件名顺序随机。如果你追求极致速度且不关心处理顺序,可使用此选项。如果处理顺序对用户可见,排序通常会带来更好体验。
如果 count 非 nil,函数只返回前 count 个文件名,或全部文件(取较少者)。count 必须是大于 0 的整数。
(directory-files "~lewis")
⇒ ("#foo#" "#foo.el#" "." ".."
"dired-mods.el" "files.texi"
"files.texi.~1~")
如果 directory 不是可读取的目录名,会抛出错误。
该工具函数在 directory 是可访问目录且不包含任何文件(即为空目录)时返回 t。在会返回 ‘.’ 和 ‘..’ 的系统上,会忽略这两项。
指向目录的符号链接视为目录。可使用 file-symlink-p 区分符号链接。
返回 directory 下所有名称匹配 regexp 的文件。该函数递归搜索指定目录及其子目录,查找 basename(不含前置目录)匹配正则表达式 regexp 的文件,并返回匹配文件的绝对文件名列表(see absolute file names)。文件名按深度优先顺序返回,即子目录中的文件排在其父目录文件之前。此外,每个子目录中的匹配文件按 basename 字母序排序。默认情况下,名称匹配 regexp 的目录不会出现在列表中;如果可选参数 include-directories 非 nil,则会包含这些目录。
默认会进入所有子目录。如果 predicate 为 t,则忽略进入子目录时发生的错误(例如无权限读取)。如果它既非 nil 也非 t,则应为一个单参数函数(参数为子目录名),返回非 nil 时才进入该目录。
默认不跟随指向子目录的符号链接;如果 follow-symlinks 非 nil,则会跟随。
从 file 开始,向上遍历目录树,查找第一个存在名称为 name(字符串)的目录,并返回该目录。如果 file 是普通文件,则从其所在目录开始搜索;否则 file 应为搜索起始目录。函数依次在起始目录、父目录、祖父目录……中查找,直到找到包含 name 的目录,或到达文件系统根目录仍未找到——后一种情况返回 nil。
参数 name 也可以是一个谓词函数。该函数会对从 file 开始遍历的每个目录调用谓词(即使 file 不是目录),传入一个参数(文件或目录名),返回非 nil 时表示找到目标目录。
如果 file 位于目录 dir 或其子目录中,该函数返回 t。如果 file 与 dir 是同一个目录,也返回 t。函数会比较两者的真实路径。如果 dir 不是已存在目录,则返回 nil。
该函数在筛选文件和处理文件名方式上与 directory-files 类似。但它不返回文件名列表,而是为每个文件返回一个列表 (filename . attributes),其中 attributes 是 file-attributes 对该文件返回的属性结构。可选参数 id-format 的含义与 file-attributes 的对应参数一致(see Definition of file-attributes)。
该正则表达式匹配除 ‘.’ 和 ‘..’ 之外的任何文件名。更精确地说,它匹配任意非空字符串中除这两个名称之外的部分。适合作为 directory-files 和 directory-files-and-attributes 的 match-regexp 参数:
(directory-files "/foo" nil directory-files-no-dot-files-regexp)
如果目录 ‘/foo’ 为空,则返回 nil。
该函数展开通配符模式 pattern,返回匹配的文件名列表。
pattern 默认为 glob / 通配符字符串,例如 ‘"/tmp/*.png"’ 或 ‘"/*/*/foo.png"’;如果可选参数 regexp 非 nil,则 pattern 可作为正则表达式使用。无论哪种方式,匹配都按子目录分别进行,不能跨父子目录匹配。
如果 pattern 是绝对文件名,返回值也为绝对路径。
如果 pattern 是相对文件名,则按当前默认目录解析。返回的文件名通常也相对当前默认目录;但如果 full 非 nil,则返回绝对路径。
该函数在当前缓冲区中插入目录 file 的列表,格式由 ls 根据 switches 控制。执行后光标位于插入文本之后。switches 可以是选项字符串,也可以是表示单个选项的字符串列表。
参数 file 可以是目录或包含通配符的文件说明。如果 wildcard 非 nil,表示将 file 视为带通配符的文件说明。
如果 full-directory-p 非 nil,表示目录列表应显示目录的完整内容。当 file 是目录且选项中不含 ‘-d’ 时应指定为 t。(ls 的 ‘-d’ 选项表示将目录本身作为文件描述,而非显示其内容。)
在大多数系统上,该函数通过运行变量 insert-directory-program 中的程序生成目录列表。如果 wildcard 非 nil,还会运行 shell-file-name 指定的 Shell 以展开通配符。
MS-DOS 和 MS-Windows 通常缺少标准 Unix 程序 ls,因此该函数用 Lisp 代码模拟其行为。
技术细节:当 switches 包含长选项 ‘--dired’ 时,insert-directory 会为 dired 做特殊处理。但通常等价的短选项 ‘-D’ 会像其他普通选项一样直接传给 insert-directory-program。
该用户选项指定为 insert-directory 生成目录列表所运行的程序。在使用 Lisp 代码生成列表的系统上忽略此选项。
大多数 Emacs Lisp 文件操作函数在作用于目录文件时会报错。例如,不能使用 delete-file 删除目录。以下是专门用于创建和删除目录的函数。
该命令创建名为 dirname 的目录。如果 parents 非 nil(交互式调用时始终为非 nil),表示若父目录不存在则先创建父目录。
作为函数调用时:如果 dirname 已作为目录存在且 parents 非 nil,make-directory 返回非 nil;如果成功创建 dirname,则返回 nil。
mkdir 是该函数的别名。
该命令创建名为 filename 的空文件。
与 make-directory 类似,若 parents 非 nil,该命令会创建所需的父目录。
如果 filename 已存在,该命令会抛出错误。
该命令将目录 dirname 复制到 newname。如果 newname 是目录名,则 dirname 会被复制为该目录下的子目录。 See 目录名。
该命令始终将复制后文件的权限模式设置为与原文件一致。
第三个参数 keep-time 非 nil 表示保留复制文件的修改时间。使用前缀参数调用时,keep-time 会被设为非 nil。
第四个参数 parents 决定是否在父目录不存在时创建它们。交互式调用时默认会创建。
第五个参数 copy-contents 若为非 nil,表示当 newname 是目录名时,直接将 dirname 的内容复制到 newname 中,而非将 dirname 作为子目录复制进去。
该命令删除名为 dirname 的目录。函数 delete-file 无法处理目录文件,必须使用 delete-directory。如果 recursive 为 nil 且目录包含任何文件,delete-directory 会抛出错误。
如果 recursive 非 nil,即使该目录或其文件在 delete-directory 处理前已被其他进程删除,也不会报错。
delete-directory 仅在父目录层级跟随符号链接。
如果可选参数 trash 非 nil 且变量 delete-by-moving-to-trash 非 nil,该命令会将文件移至系统回收站而非直接删除。
See Miscellaneous File Operations in The GNU Emacs Manual。交互式调用时:若无前缀参数,trash 为 t;否则为 nil。
你可以为特定文件名实现特殊处理逻辑,这被称为将这些名称设为魔法(magic)文件名。该特性的主要用途是实现远程文件访问(see Remote Files in The GNU Emacs Manual)。
要定义一类魔法文件名,你需要提供一个正则表达式来界定该类名称(所有匹配该正则的名称),并提供一个处理器函数,为匹配的文件名实现所有 Emacs 基础文件操作。
变量 file-name-handler-alist 存储处理器列表,以及决定何时应用每个处理器的正则表达式。列表中每个元素的格式如下:
(regexp . handler)
所有用于文件访问和文件名转换的 Emacs 基础函数都会检查给定文件名是否匹配 file-name-handler-alist。
如果文件名匹配 regexp,这些基础函数会通过调用 handler 来处理该文件。
传给 handler 的第一个参数是基础函数名(符号形式),后续参数是传给该基础函数的参数。(这些参数中的第一个通常是文件名本身。)例如,执行以下代码时:
(file-exists-p filename)
如果 filename 对应的处理器是 handler,则 handler 会被这样调用:
(funcall handler 'file-exists-p filename)
当一个函数接收两个或更多必须是文件名的参数时,会检查每个参数对应的处理器。例如,执行以下代码时:
(expand-file-name filename dirname)
会先检查 filename 的处理器,再检查 dirname 的处理器。无论匹配到哪个,handler 都会被这样调用:
(funcall handler 'expand-file-name filename dirname)
此时 handler 需要自行判断是处理 filename 还是 dirname。
如果指定文件名匹配多个处理器,则匹配位置在文件名中起始位置最晚的处理器优先。选择此规则是为了让解压缩等处理器先于远程文件访问等处理器执行。
以下是魔法文件名处理器需要处理的操作:
abbreviate-file-name, access-file,
add-name-to-file, byte-compiler-base-file-name,
copy-directory, copy-file,
delete-directory, delete-file,
diff-latest-backup-file,
directory-file-name,
directory-files,
directory-files-and-attributes,
dired-compress-file, dired-uncache,
exec-path, expand-file-name,
file-accessible-directory-p,
file-acl,
file-attributes,
file-directory-p,
file-equal-p,
file-executable-p, file-exists-p,
file-group-gid, file-in-directory-p,
file-local-copy, file-locked-p,
file-modes, file-name-all-completions,
file-name-as-directory,
file-name-case-insensitive-p,
file-name-completion,
file-name-directory,
file-name-nondirectory,
file-name-sans-versions, file-newer-than-file-p,
file-notify-add-watch, file-notify-rm-watch,
file-notify-valid-p,
file-ownership-preserved-p,
file-readable-p, file-regular-p,
file-remote-p, file-selinux-context,
file-symlink-p, file-system-info,
file-truename, file-user-uid,
file-writable-p,
find-backup-file-name,
get-file-buffer,
insert-directory,
insert-file-contents,
list-system-processes,
load, lock-file,
make-auto-save-file-name,
make-directory,
make-lock-file-name,
make-nearby-temp-file,
make-process,
make-symbolic-link,
memory-info, process-attributes, process-file,
rename-file, set-file-acl, set-file-modes,
set-file-selinux-context, set-file-times,
set-visited-file-modtime, shell-command,
start-file-process,
substitute-in-file-name,
temporary-file-directory,
unhandled-file-name-directory,
unlock-file,
vc-registered,
verify-visited-file-modtime,
write-region.
处理 insert-file-contents 的处理器通常需要在 visit 参数非 nil 时清除缓冲区的修改标记(使用 (set-buffer-modified-p nil))。这同时也会解锁被锁定的缓冲区。
处理器函数必须处理上述所有操作,以及未来可能新增的其他操作。它无需自行实现所有操作——对于无需特殊处理的操作,可重新调用基础函数以常规方式处理。对于无法识别的操作,应始终重新调用基础函数。实现方式如下:
(defun my-file-handler (operation &rest args) ;; First check for the specific operations ;; that we have special handling for. (cond ((eq operation 'insert-file-contents) ...) ((eq operation 'write-region) ...) ... ;; Handle any operation we don’t know about. (t (let ((inhibit-file-name-handlers (cons 'my-file-handler (and (eq inhibit-file-name-operation operation) inhibit-file-name-handlers))) (inhibit-file-name-operation operation)) (apply operation args)))))
当处理器函数决定调用 Emacs 常规基础函数处理当前操作时,需要防止基础函数再次调用同一个处理器,从而导致无限递归。
上述示例展示了如何通过变量 inhibit-file-name-handlers 和 inhibit-file-name-operation 实现这一点。
务必严格按照示例中的方式使用这些变量——在多处理器场景下,以及处理包含多个可能各有处理器的文件名的操作时,细节对正确行为至关重要。
对于文件实际访问无需特殊处理的处理器(例如仅为远程文件名实现主机名补全的处理器),应设置非 nil 的 safe-magic 属性。
例如,Emacs 通常会保护 PATH 中找到的目录名,若其看起来像魔法文件名,则在前面添加 ‘/:’ 以避免被识别为魔法文件名。
但如果对应的处理器的 safe-magic 属性为非 nil,则不会添加 ‘/:’。
文件名处理器可设置 operations 属性,声明其需要做特殊处理的操作。
若该属性值非 nil,则应为操作列表;此时只有列表中的操作会调用该处理器。
这能避免低效调用,主要用于自动加载的处理器函数,确保仅在有实际工作要做时才加载它们。
简单地将所有操作委托给常规基础函数是不可行的。例如,如果文件名处理器作用于 file-exists-p,则必须自行处理 load,因为常规的 load 代码在此场景下无法正常工作。
但如果处理器通过 operations 属性声明不处理 file-exists-p,则无需对 load 做特殊处理。
该变量存储当前被禁止用于特定操作的处理器列表。
当前禁止某些处理器生效的操作名称。
该函数返回文件名 file 对应的处理器函数,若无则返回 nil。参数 operation 应为要对文件执行的操作——即调用处理器时作为第一个参数传入的值。
如果 operation 等于 inhibit-file-name-operation,或未出现在处理器的 operations 属性中,该函数返回 nil。
如果文件 filename 不在本地主机上,该函数会将其复制到本地主机的普通非魔法文件中。
指向其他机器文件的魔法文件名应处理 file-local-copy 操作。
用于远程文件访问以外用途的魔法文件名不应处理 file-local-copy,此时该函数会将文件视为本地文件。
如果 filename 是本地文件(无论是否为魔法文件),该函数不执行任何操作并返回 nil。否则返回本地副本的文件名。
该函数检查 filename 是否为远程文件。如果 filename 是本地文件(非远程),返回 nil。
如果确实是远程文件,返回标识远程系统的字符串。
该标识符字符串可包含主机名、用户名,以及指定访问远程系统方式的字符。例如,文件名 /sudo::/some/file 的远程标识符字符串是 /sudo:root@localhost:。
如果 file-remote-p 对两个不同文件名返回相同标识符,表示它们存储在同一文件系统上,且可相对彼此本地访问。
这意味着例如可以启动一个远程进程同时访问这两个文件。文件名处理器的实现者需要确保该原则有效。
identification 指定要返回的标识符部分。identification 可以是符号 method、user、host 或 localname;
其他值视为 nil,表示返回完整的标识符字符串。在上述示例中,远程 user 标识符字符串为 root。
如果远程文件 file 不包含访问方式、用户名或主机名,则返回相应的默认值。
identification 为 localname 时返回的字符串可能因是否存在现有连接而不同。
特定的文件名处理器实现可支持更多 identification 符号;例如 See Tramp 还支持 hop 符号。
如果 connected 非 nil,即使 filename 是远程文件,若 Emacs 与对应主机无网络连接,该函数也返回 nil。
这在需要避免因无连接而产生连接延迟时非常有用。如果 connected 为 never,则**绝不**使用现有连接返回标识符(其他行为与 nil 相同)。
这可防止任何连接相关的逻辑,例如展开文件名的本地部分。
该函数返回一个非魔法目录名。对于非魔法文件名 filename,返回对应的目录名(see 目录名)。
对于魔法文件名 filename,调用其文件名处理器,由处理器决定返回值。
如果 filename 无法被本地进程访问,文件名处理器应返回 nil 以标识此情况。
这在运行子进程时非常有用:每个子进程都需要一个非魔法目录作为当前目录,该函数是获取此类目录的理想方式。
该函数返回 filename 的本地部分(local part)。这是文件名在远程主机上标识文件的部分,通常通过从远程文件名中移除指定远程主机和访问方式的部分得到。例如:
(file-local-name "/ssh:user@host:/foo/bar")
⇒ "/foo/bar"
对于远程文件名 filename,该函数返回的文件名可直接用作远程进程的参数(see Creating an Asynchronous Process 和 see Creating a Synchronous Process),也可作为要在远程主机上运行的程序名。 如果 filename 是本地文件,该函数原样返回。
为提升性能,远程文件的属性可被缓存。如果这些属性在 Emacs 控制之外被修改,缓存值会失效,必须重新读取。
当该变量设为 nil 时,缓存值永不过期。使用此设置时需谨慎,仅当确定除 Emacs 外无其他程序修改远程文件时使用。
设为 t 时,永不使用缓存值。这是最安全的设置,但可能导致性能下降。
折中方案是将其设为正数,表示缓存值自缓存时起可使用指定秒数。 如果定期检查远程文件,可将该变量临时绑定为小于连续检查间隔的值。例如:
(defun display-time-file-nonempty-p (file)
(let ((remote-file-name-inhibit-cache
(- display-time-interval 5)))
(and (file-exists-p file)
(< 0 (file-attribute-size
(file-attributes
(file-chase-links file)))))))
without-remote-files 宏在禁用远程文件的文件名处理器的情况下求值 body 中的表达式。
这些文件名会被按字面量处理。
该宏仅应在明确不会出现远程文件,或有意不处理远程文件名的场景中使用。
它还能减少对 file-name-handler-alist 的检查,提升代码性能。
Emacs 会执行多个步骤,在缓冲区中的数据(文本、文本属性,以及可能的其他信息)与适合存入文件的表示形式之间互相转换。本节介绍执行这种 格式转换(format conversion)的基础函数,即用于将文件读入缓冲区的 insert-file-contents,以及用于将缓冲区写入文件的 write-region。
函数 insert-file-contents 的执行流程:
format-alist 中条目的定义处理格式;
after-insert-file-functions 中的函数。
函数 write-region 的执行流程:
write-region-annotate-functions中的函数;
format-alist 中条目的定义处理格式;
以上体现了底层操作的对称性;读取与写入的处理顺序恰好相反。本节后续内容介绍围绕上述三个变量的两种机制,以及一些相关函数。字符编码与解码的详细说明参见 Coding Systems。
两种机制中更为通用的一种由变量 format-alist 控制,该变量是一个 文件格式 规范列表,用于描述文件中用于表示 Emacs 缓冲区数据的文本形式。读取与写入的描述是配对的,因此我们称之为“往返(round-trip)”规范(非配对规范参见 see 分步格式规范)。
该列表为每个已定义的文件格式保存一条格式定义。每条格式定义为如下形式的列表:
(name doc-string regexp from-fn to-fn modify mode-fn preserve)
格式定义中各元素的含义如下:
该格式的名称。
该格式的文档字符串。
用于识别采用此格式的文件的正则表达式。若为 nil,则该格式不会被自动应用。
用于解码该格式数据的 Shell 命令或函数(即将文件数据转换为 Emacs 常规数据表示形式)。
Shell 命令以字符串形式表示;Emacs 会将该命令作为过滤器执行转换。
若 from-fn 为函数,它会接收两个参数 begin 和 end,指定缓冲区中需要转换的区域。该函数应通过原地编辑的方式修改文本。由于这可能改变文本长度,from-fn 应当返回修改后的结束位置。
from-fn 的一项职责是确保文件开头不再匹配 regexp,否则可能会被重复调用。此外,from-fn 不得涉及正在解码的文件或缓冲区之外的其他缓冲区或文件,否则用于格式处理的内部缓冲区可能被覆盖。
用于编码该格式数据的 Shell 命令或函数——即将 Emacs 常规数据表示形式转换为该格式。
若 to-fn 为字符串,则表示一条 Shell 命令;Emacs 会将该命令作为过滤器执行转换。
若 to-fn 为函数,它会接收三个参数:begin 和 end 指定缓冲区中需要转换的区域,buffer 指定目标缓冲区。转换方式有两种:
(position . string),其中 position 为待写入文本中的相对位置,string 为要在该位置添加的注解。to-fn 返回时,列表必须按位置升序排列。
当 write-region 实际将缓冲区文本写入文件时,会在对应位置插入指定的注解。整个过程不会修改缓冲区内容。
to-fn 不得涉及正在编码的文件或缓冲区之外的其他缓冲区或文件,否则用于格式处理的内部缓冲区可能被覆盖。
一个标志位;若编码函数会修改缓冲区则为 t,若通过返回注解列表实现则为 nil。
访问从该格式转换而来的文件后需要调用的次要模式函数。该函数接收一个整数参数 1,用于告知次要模式函数启用该模式。
一个标志位;若 format-write-file 不应将该格式从 buffer-file-format 中移除则为t。
函数 insert-file-contents 在读取指定文件时会自动识别文件格式。它将文件开头的文本与格式定义中的正则表达式进行匹配,若匹配成功则调用对应格式的解码函数,之后再次检查所有已知格式,直到没有格式可应用为止。
通过 find-file-noselect 或相关命令访问文件时同样会执行格式转换(因为其内部调用了 insert-file-contents);同时会为每个解码的格式调用对应的模式函数,并将格式名称列表保存到缓冲区局部变量 buffer-file-format 中。
该变量记录所访问文件的格式。更准确地说,它是访问当前缓冲区对应文件时解码所用的文件格式名称列表。该变量在所有缓冲区中均为缓冲区局部变量。
当write-region向文件写入数据时,会先按照buffer-file-format列表中的顺序,调用对应格式的编码函数。
该命令以 format 指定的格式将当前缓冲区内容写入文件 file,其中 format 为格式名称列表。它会以 format 为基础,追加 buffer-file-format 中 preserve 标志为非 nil 且未出现在 format 中的元素,构建实际使用的格式。随后更新 buffer-file-format 为该格式,作为后续保存的默认格式。除 format 参数外,该命令与 write-file 类似。其中 confirm 的含义与交互处理方式和 write-file 的对应参数一致,see Definition of write-file。
该命令打开文件 file 并按照 format 指定的格式进行转换。若后续保存该缓冲区,format 会作为默认格式。
参数 format 为格式名称列表。若 format 为 nil,则不执行转换。交互模式下,为 format 直接按 RET 即指定为 nil。
该命令插入文件 file 的内容,并按照 format 指定的格式进行转换。若 beg 和 end 非 nil,则指定读取文件的部分区域,用法与 insert-file-contents 相同(see 从文件读取)。
返回值与 insert-file-contents 一致:为包含文件绝对路径和插入数据长度(转换后)的列表。
参数 format 为格式名称列表。若 format 为 nil,则不执行转换。交互模式下,为 format 直接按 RET 即指定为 nil。
该变量指定自动保存所用的格式。其值为格式名称列表,与 buffer-file-format 形式相同;但在写入自动保存文件时会替代 buffer-file-format 使用。若值为 t(默认值),则自动保存使用与常规保存相同的格式。该变量在所有缓冲区中均为缓冲区局部变量。
与上一小节介绍的往返格式规范不同(see 往返格式规范),你可以使用变量
after-insert-file-functions 和 write-region-annotate-functions
分别控制读取和写入时的转换过程。
转换从一种表示形式开始,并生成另一种表示形式。如果只需要执行一次转换,就不会出现起始数据的冲突。 但如果涉及多次转换,当两个转换都需要以同一份原始数据为起点时,就可能产生冲突。
这种情况在 write-region 处理文本属性转换时最容易理解。例如,缓冲区中第 42 位的字符是
‘X’,并带有文本属性 foo。如果对 foo 的转换是向缓冲区插入类似
‘FOO:’ 的内容,那么第 42 位的字符就会从 ‘X’ 变成 ‘F’,
下一次转换将直接从错误的数据开始。
为避免冲突,协作式转换不会修改缓冲区,而是通过指定注解(annotations)来实现。注解是形如
(position . string) 的列表,并按 position 升序排列。
如果存在多个转换,write-region 会将它们的注解合并为一个有序列表。
之后,当缓冲区中的文本真正写入文件时,会在对应位置插入这些注解。
整个过程不会修改缓冲区内容。
与之相反,读取时,与文本混合在一起的注解会被立即处理。
insert-file-contents 会将光标移到待转换文本的开头,
然后以该文本长度为参数调用转换函数。这些函数执行完毕后应保持光标位于插入文本的开头。
这种读取方式是合理的,因为第一个转换器移除的注解不会被后续转换器误处理。
每个转换函数应当扫描并识别自己关心的注解,移除该注解,修改缓冲区文本(例如设置文本属性),
然后返回修改后的文本长度。一个函数的返回值会作为下一个函数的参数。
write-region 要调用的函数列表。列表中的每个函数会接收两个参数:
待写入区域的起始位置和结束位置。这些函数不应修改缓冲区内容,而应返回注解。
特殊情况下,函数返回时可以切换当前缓冲区。Emacs 会认为该当前缓冲区包含需要输出的修改后文本,
因此会将 write-region 的 start 和 end 参数
分别改为新缓冲区的 point-min 和 point-max,
同时丢弃之前所有注解,视为已由该函数处理完毕。
如果该变量非 nil,其值应为一个函数。
该函数会在 write-region 执行完成后被无参调用。
如果 write-region-annotate-functions 中的某个函数返回时切换了当前缓冲区,
Emacs 会多次调用 write-region-post-annotation-function,
依次从最后一个当前缓冲区往回调用,直到原始缓冲区。
因此,write-region-annotate-functions 中的函数可以创建一个缓冲区,
在该缓冲区内将此变量局部设为 kill-buffer,
填入修改后的文本并设为当前缓冲区,该缓冲区会在 write-region 结束后被自动杀死。
insert-file-contents 调用此列表中的每个函数时,
会传入一个参数:已插入的字符数,并且光标位于插入文本的开头。
每个函数应保持光标位置不变,并返回经该函数修改后插入文本的新字符数。
我们欢迎用户编写 Lisp 程序,利用这些钩子在文件中保存和读取文本属性, 从而尝试各种数据格式并找到优秀的方案。最终我们希望用户能开发出通用、好用的扩展, 以便集成到 Emacs 中。
我们建议不要尝试将任意 Lisp 对象作为文本属性的名称或值—— 因为通用性过强的程序往往难以编写,且运行缓慢。 更好的做法是选择一组既灵活又易于编码的数据类型。
备份文件与自动保存文件是 Emacs 用于保护用户免受系统崩溃或自身操作失误影响的两种机制。 自动保存会保留当前编辑会话中较早的文本内容;备份文件则保存当前会话开始之前的文件内容。
备份文件(backup file)是你正在编辑的文件旧内容的副本。Emacs 会在你首次将缓冲区保存到其所访问的文件时创建备份。 因此,备份文件通常包含当前编辑会话开始前的文件内容。备份文件一旦生成,其内容通常不再改变。
备份通常通过将被访问文件重命名为新名称实现。你也可以选择通过复制原文件来创建备份文件。 这一选择对拥有多个名称的文件会产生不同影响;同时也可能决定被编辑文件的归属权是保持原所有者, 还是变为当前编辑用户所有。
默认情况下,Emacs 为每个编辑过的文件只保留一份备份。你也可以启用带编号的备份, 这样每次新备份都会使用新名称。不再需要的旧编号备份可以手动删除,也可由 Emacs 自动删除。
出于性能考虑,操作系统可能不会立即将备份文件内容写入辅助存储, 或者在其中一方被修改前将备份数据与原文件做别名映射。See 文件与辅助存储。
该函数在合适时为当前缓冲区所访问的文件创建备份。它会在 save-buffer 首次保存缓冲区前被调用。
若备份通过重命名方式创建,返回值为形如 (modes extra-alist backupname) 的 cons 单元,
其中 modes 是原文件的权限位,与 file-modes 返回值一致(see 测试文件可访问性);
extra-alist 是描述原文件扩展属性的 alist,与 file-extended-attributes 返回值一致(see 文件扩展属性);
backupname 为备份文件名称。
在其他所有情况下(即通过复制创建备份或未创建备份),该函数返回 nil。
该缓冲区局部变量标记该缓冲区对应的文件是否已因本缓冲区而创建过备份。若其值非 nil,
表示备份文件已写入;否则文件应在下次保存时进行备份(前提是备份已启用)。
该变量为永久局部变量,kill-all-local-variables 不会改变它。
该变量决定是否创建备份文件。若其值非 nil,则 Emacs 在每个文件首次保存时创建备份,
前提是 backup-inhibited 为 nil(见下文)。
下面示例展示如何仅在 Rmail 缓冲区中关闭 make-backup-files,其他位置保持不变。
将其设为 nil 可阻止 Emacs 为这些文件创建备份,从而节省磁盘空间。(可将此代码放入初始化文件。)
(add-hook 'rmail-mode-hook
(lambda () (setq-local make-backup-files nil)))
该变量的值为一个函数,会在特定时机被调用,以决定某文件是否需要创建备份文件。
该函数接收一个参数:待判断的绝对文件名。若函数返回 nil,则该文件禁用备份;
否则由本节其他变量决定是否以及如何创建备份。
默认值为 normal-backup-enable-predicate,它会排除 temporary-file-directory
和 small-temporary-file-directory 中的文件。
若该变量非 nil,则禁用备份。它记录了对被访问文件应用 backup-enable-predicate 的判断结果。
其他基于所访问文件控制备份的机制也可合理使用该变量。例如,VC 会将其设为非 nil,
以避免为版本控制系统管理的文件创建备份。
该变量为永久局部变量,因此切换主模式不会丢失其值。主模式不应直接设置此变量,
而应修改 make-backup-files。
该变量的值是一个由文件名匹配规则和备份目录组成的 alist。每个元素格式为:
(regexp . directory)
名称匹配 regexp 的文件,其备份将保存在 directory 中。directory 可以是相对或绝对路径。 若为绝对路径,则所有匹配文件的备份都会存入同一目录;目录中的备份文件名将使用原文件完整路径, 并将所有目录分隔符替换为 ‘!’ 以避免冲突。若文件系统会截断过长名称,则该方式可能无法正常工作。
若希望所有备份统一存入一个目录,alist 可只包含一个元素,将 ‘"."’ 与对应目录关联。
若该变量为 nil(默认值)或无法匹配某文件名,则备份会创建在原文件所在目录。
在不支持长文件名的 MS-DOS 文件系统中,该变量始终被忽略。
该变量的值为用于生成备份文件名的函数。函数 make-backup-file-name 会调用它。
See 备份文件命名。
该变量可设为缓冲区局部变量,以便对特定文件执行特殊处理。若修改此函数,
通常也需要同步修改 backup-file-name-p 和 file-name-sans-versions。
Emacs 可以通过两种方式创建备份文件:
第一种方式(重命名)为默认方式。
若变量 backup-by-copying 非 nil,则表示使用第二种方式,
即复制原文件并用缓冲区新内容覆盖它。若变量 file-precious-flag 非 nil,
也会产生同样效果(这是其主要作用之外的附加行为)。See 保存缓冲区。
若该变量非 nil,Emacs 将始终通过复制方式创建备份文件。默认值为 nil。
下面三个变量在非 nil 时,会在特定场景下使用第二种备份方式。
对于不属于这些特殊场景的文件,它们不会产生任何影响。
若该变量非 nil,Emacs 对拥有多个名称(硬链接)的文件采用复制方式创建备份。默认值为 nil。
该变量仅在 backup-by-copying 为 nil 时有效,
因为只要后者非 nil,就会始终使用复制方式。
若该变量非 nil(默认值),当重命名会改变文件的所有者或用户组时,
Emacs 将采用复制方式创建备份。
若重命名不会改变文件所有者或用户组(即文件所有者为当前用户, 且用户组与该用户在此目录新建文件的默认用户组一致),则该变量无效。
该变量仅在 backup-by-copying 为 nil 时有效。
若该变量非 nil,其行为与 backup-by-copying-when-mismatch 相同,
但仅对特定用户 ID 和组 ID 生效:即小于或等于某个数值的 ID。
该变量的值即为这个数值。
例如,若将 backup-by-copying-when-privileged-mismatch 设为 0,
则仅在必要时为超级用户与 0 号用户组的文件使用复制备份,以避免文件所有者发生变化。
默认值为 200。
若文件名为 foo,其编号备份版本的名称为 foo.~v~, 其中 v 为不同整数,例如:foo.~1~、foo.~2~、foo.~3~、……、foo.~259~ 等。
该变量控制是创建单个无编号备份文件,还是创建多个编号备份文件。
nil若所访问文件已有编号备份,则继续创建编号备份;否则不创建。此为默认行为。
never不创建编号备份。
创建编号备份。
使用编号备份最终会产生大量备份版本,需要进行清理。 Emacs 可以自动删除,也可以询问用户后再删除。
该变量的值为创建新编号备份时保留的最新版本数量,新建的备份也计入此数量。默认值为 2。
该变量的值为创建新编号备份时保留的最旧版本数量。默认值为 2。
若存在编号为 1、2、3、5、7 的备份,且上述两个变量均为 2,
则编号 1 和 2 作为旧版本保留,编号 5 和 7 作为新版本保留;编号 3 的备份为多余版本。
函数 find-backup-file-name(see 备份文件命名)负责判断应删除哪些备份版本,
但不会实际执行删除操作。
若该变量为 t,保存文件时会直接静默删除多余的备份版本。
若为 nil,则在删除前向用户请求确认。
其他情况下则不会删除任何多余备份。
该变量指定在 Dired 命令 .(dired-clean-directory)中保留的最新备份版本数量,
作用与创建新备份时的 kept-new-versions 相同。默认值为 2。
本节所介绍的函数主要用于文档记录,你可以通过重新定义它们来自定义备份文件的命名规则。 如果修改了其中一个,通常也需要同步修改其余相关函数。
该函数在 filename 可能为备份文件名时返回非 nil 值。
它仅检查名称本身,不检查该文件是否实际存在。
(backup-file-name-p "foo")
⇒ nil
(backup-file-name-p "foo~")
⇒ 3
该函数的标准定义如下:
(defun backup-file-name-p (file) "Return non-nil if FILE is a backup file \ name (numeric or not)..." (string-match "~\\'" file))
可见,该函数在文件名以 ‘~’ 结尾时返回非 nil 值。
(我们使用反斜杠将文档字符串的第一行拆分为文本中的两行,但字符串本身仍为单行。)
这一简单表达式被独立为一个函数,便于重新定义以实现自定义。
该函数返回一个字符串,作为文件 filename 的无编号备份文件名。 在类 Unix 系统上,仅需在 filename 后追加波浪号。
大多数操作系统中,该函数的标准定义如下:
(defun make-backup-file-name (file) "Create the non-numeric backup file name for FILE..." (concat file "~"))
你可以通过重定义此函数来修改备份文件命名规则。下面示例重定义 make-backup-file-name,
使其在追加波浪号的同时在文件名前添加 ‘.’:
(defun make-backup-file-name (filename)
(expand-file-name
(concat "." (file-name-nondirectory filename) "~")
(file-name-directory filename)))
(make-backup-file-name "backups.texi")
⇒ ".backups.texi~"
Emacs 的部分功能(包括部分 Dired 命令)假定备份文件名以 ‘~’ 结尾。 若不遵循该约定,不会导致严重问题,但这些命令的效果可能不如预期。
该函数计算 filename 新备份文件的文件名,同时可能提议删除部分已有备份文件。
find-backup-file-name 返回一个列表,其 CAR 为新备份文件名,CDR 为建议删除的备份文件列表。
返回值也可为 nil,表示不创建备份。
变量 kept-old-versions 和 kept-new-versions 决定应保留的备份版本,
本函数会将这些版本排除在 CDR 列表之外。See 创建与删除编号备份文件。
下例中,返回值表示新备份文件名为 ~rms/foo.~5~, ~rms/foo.~3~ 为多余版本,调用方可考虑删除。
(find-backup-file-name "~rms/foo")
⇒ ("~rms/foo.~5~" "~rms/foo.~3~")
该函数返回 filename 所有备份文件名的列表,若无备份则返回 nil。
文件按修改时间降序排列,最新文件排在最前。
该函数返回 file-backup-file-names 所返回列表的第一个元素。
部分文件比较命令使用该函数,以便自动将文件与其最新备份进行对比。
Emacs 会定期保存你正在访问的所有文件,这一机制称为自动保存(auto-saving)。 自动保存可在系统崩溃时避免大量工作丢失。默认情况下,每输入 300 次按键或空闲约 30 秒后触发自动保存。 面向用户的自动保存说明参见 Auto-Saving: Protection Against Disasters in The GNU Emacs Manual。 本节介绍实现自动保存的函数及控制变量。
该缓冲区局部变量为当前缓冲区自动保存所用的文件名。若缓冲区无需自动保存,其值为 nil。
buffer-auto-save-file-name
⇒ "/xcssun/users/rms/lewis/#backups.texi#"
自动保存模式的模式命令,为缓冲区局部次要模式。启用自动保存模式后,缓冲区将开启自动保存功能。 调用规则与其他次要模式命令一致(see 编写次要模式的规范)。
与大多数次要模式不同,不存在 auto-save-mode 变量。
当 buffer-auto-save-file-name 非 nil 且 buffer-saved-size(见下文)非零时,自动保存模式启用。
该变量为一组转换规则,用于在生成自动保存文件名前对缓冲区文件名进行转换。
每条转换规则为形如 (regexp replacement [uniquify]) 的列表。
regexp 为匹配文件名的正则表达式,匹配成功后使用 replace-match 将匹配部分替换为 replacement。
若可选元素 uniquify 非 nil,自动保存文件名由转换后文件名的目录部分,
与原缓冲区文件名拼接而成,其中所有目录分隔符替换为 ‘!’ 以避免冲突。
(若文件系统会截断过长名称,该方式可能无法正常工作。)
若 uniquify 为 secure-hash-algorithms 成员之一,
Emacs 会对缓冲区文件名应用对应安全哈希算法生成非目录部分,避免文件名过长。
列表中的转换规则按顺序尝试,某条规则生效后结果即为最终结果,不再继续尝试后续规则。
默认值会将远程文件的自动保存文件放入临时目录(see 生成唯一文件名)。
在不支持长文件名的 MS-DOS 文件系统中,该变量始终被忽略。
该函数在 filename 符合自动保存文件名格式时返回非 nil 值。
其采用常规命名规则:以井号 ‘#’ 开头和结尾的文件名为自动保存文件名。
参数 filename 不应包含目录部分。
(make-auto-save-file-name)
⇒ "/xcssun/users/rms/lewis/#backups.texi#"
(auto-save-file-name-p "#backups.texi#")
⇒ 0
(auto-save-file-name-p "backups.texi")
⇒ nil
该函数返回当前缓冲区自动保存所用文件名,即在原文件名前后添加井号 ‘#’。
该函数不会检查变量 auto-save-visited-file-name(见下文),调用者应先判断该变量。
(make-auto-save-file-name)
⇒ "/xcssun/users/rms/lewis/#backups.texi#"
若该变量非 nil,Emacs 会将缓冲区自动保存至其所访问的原文件,
即自动保存与编辑文件为同一文件。通常该变量为 nil,
自动保存文件使用由 make-auto-save-file-name 生成的独立名称。
修改该变量后,已有缓冲区需下次重新启用自动保存模式时新值才会生效。
若自动保存模式已启用,自动保存会继续使用原文件名,直至再次调用 auto-save-mode。
注意:将该变量设为非 nil 不会改变自动保存与普通保存的区别,
例如缓冲区自动保存时不会运行 保存缓冲区 中所述的钩子。
若当前缓冲区自上次读取或保存后已执行自动保存,该函数返回 t。
该函数将当前缓冲区标记为已自动保存。缓冲区文本再次修改前不会重复自动保存。函数返回 nil。
该变量以输入事件次数为单位指定自动保存的触发频率。 每读取该数量的新增输入事件后,Emacs 对所有启用自动保存的缓冲区执行自动保存。 设为 0 可禁用基于输入字符数的自动保存。
该变量以秒为单位指定触发自动保存的空闲时间。 用户空闲达到该时长后,Emacs 对所有启用自动保存的缓冲区执行自动保存。 (若当前缓冲区较大,指定超时时间会随大小倍增,百万字节缓冲区的系数接近 4。)
若值为 0 或 nil,则不会因空闲触发自动保存,仅按 auto-save-interval 指定的输入事件次数触发。
该常规钩子在每次自动保存即将执行时运行。
若该变量非 nil,访问文件的缓冲区默认启用自动保存,否则不启用。
该函数对所有需要自动保存的缓冲区执行自动保存, 即保存所有启用自动保存且自上次自动保存后已修改的缓冲区。
若有缓冲区被自动保存,do-auto-save 通常会在回显区显示 ‘Auto-saving...’。
若 no-message 非 nil,则抑制该提示信息。
若 current-only 非 nil,仅对当前缓冲区执行自动保存。
若 delete-auto-save-files 非 nil,该函数删除当前缓冲区的自动保存文件。
每次保存缓冲区时都会调用该函数。
除非 force 非 nil,否则仅删除当前 Emacs 会话中、上次正式保存后生成的自动保存文件。
该变量由 delete-auto-save-file-if-necessary 使用。
若其非 nil,Emacs 在执行正式保存(保存至所访问文件)时删除自动保存文件,
可节省磁盘空间并清理目录。
若所访问文件名称已变更,该函数调整当前缓冲区的自动保存文件名, 并对当前会话中已生成的自动保存文件执行重命名。若文件名未变更,则不执行任何操作。
该缓冲区局部变量的值为缓冲区上次读取、保存或自动保存时的长度, 用于检测缓冲区大小是否大幅缩减,并据此关闭自动保存。
若值为 −1,表示因缓冲区大小显著减小,本缓冲区临时关闭自动保存。 显式保存缓冲区会为该变量存入正值,从而重新启用自动保存。 开启或关闭自动保存模式也会更新该变量,清除大小显著减小的标记。
若值为 −2,表示本缓冲区忽略大小变化,尤其不会因缓冲区大小变化临时关闭自动保存。
若该变量非 nil,指定用于记录所有自动保存文件名的文件。
每次 Emacs 执行自动保存时,会为每个启用自动保存的缓冲区写入两行信息:
第一行为所访问文件名称(无对应文件则为空),第二行为自动保存文件名。
Emacs 正常退出时会删除该文件;若 Emacs 崩溃,可通过该文件查找可能丢失工作的自动保存文件。
recover-session 命令使用该文件定位自动保存文件。
该文件默认位于用户主目录,以 ‘.saves-’ 开头,包含 Emacs 进程 ID 与主机名。
Emacs 读取初始化文件后,若你尚未将 auto-save-list-file-name 设为非 nil,
会基于此前缀并追加主机名与进程 ID 初始化该变量。
若在初始化文件中将其设为 nil,Emacs 则不会初始化 auto-save-list-file-name。
如果你对某个文件进行了大量修改,随后又改变主意不想要这些改动,可以使用 revert-buffer 命令重新读取该文件的先前版本,从而放弃所有修改。See Reverting a Buffer in The GNU Emacs Manual。
该命令使用磁盘上已访问文件的内容替换当前缓冲区文本。此操作会撤销自文件被访问或保存以来的所有改动。
默认情况下,如果最新的自动保存文件比已访问文件更新,且参数 ignore-auto 为 nil,
revert-buffer 会询问用户是否改用该自动保存文件。当你以交互方式调用此命令时,若没有数值型前缀参数,ignore-auto 为 t;因此,交互模式下默认不检查自动保存文件。
通常,revert-buffer 在修改缓冲区前会请求确认;但如果参数 noconfirm 为非 nil 值,
revert-buffer 则不会请求确认。
该命令通常会通过 normal-mode 重新初始化缓冲区的主模式和次模式。但如果 preserve-modes
为非 nil 值,各类模式则保持不变。
恢复操作会借助 insert-file-contents 的替换功能,尝试保留缓冲区中的标记位置。如果执行恢复前缓冲区内容与文件内容完全一致,恢复操作会保留所有标记。如果二者不一致,恢复操作会修改缓冲区;这种情况下,它会保留缓冲区开头与结尾未改动文本(若有)中的标记。保留更多额外标记可能会引发问题。
从非文件来源恢复缓冲区时,标记通常不会被保留,具体行为取决于对应 revert-buffer-function 的实现。
revert-buffer 在执行过程中会将此变量绑定为非 nil 值。
你可以通过设置本节后续介绍的变量,自定义 revert-buffer 的工作方式。
该变量保存一份无需询问即可直接恢复的文件列表,其值为一组正则表达式。如果被访问的文件名匹配其中任一正则表达式,且文件在磁盘上已变更但缓冲区未被修改,revert-buffer 会直接恢复文件而不向用户请求确认。
部分主模式会通过为这些变量设置缓冲区局部绑定,来自定义 revert-buffer:
该变量的值为用于恢复当前缓冲区的函数。它应当是一个接受两个可选参数、执行恢复工作的函数。这两个可选参数 ignore-auto 与 noconfirm,即 revert-buffer 接收到的参数。
像目录编辑模式(Dired模式)这类场景中,编辑的文本并非文件内容,而是可以通过其他方式重新生成,这类模式可以为该变量设置缓冲区局部值,指定一个专用函数来重新生成内容。
该变量的值指定了恢复缓冲区时用于插入更新后内容的函数。该函数接收两个参数:第一个是要使用的文件名;第二个是当用户要求读取自动保存文件时为 t。
某个模式选择修改此变量而非 revert-buffer-function,原因是避免重复或替换 revert-buffer 的其余逻辑:包括请求确认、清空撤销列表、确定合适的主模式,以及运行下文列出的钩子。
该常规钩子由默认的 revert-buffer-function 在插入修改后内容之前运行。自定义的 revert-buffer-function 可能运行也可能不运行此钩子。
该常规钩子由默认的 revert-buffer-function 在插入修改后内容之后运行。自定义的 revert-buffer-function 可能运行也可能不运行此钩子。
该变量的值指定一组用于保存缓冲区状态的函数。在执行恢复操作前,列表中的每个函数会被无参调用,且应返回一个用于保存特定状态(例如只读状态)的匿名函数。恢复操作完成后,每个匿名函数会按列表顺序依次调用,将保存的状态恢复到已恢复的缓冲区中。
Emacs 可以自动恢复缓冲区。对于访问文件的缓冲区,该功能默认启用。下文说明如何为新型缓冲区添加自动恢复支持。
首先,这类缓冲区必须定义合适的 revert-buffer-function 与 buffer-stale-function。
该变量的值指定一个用于检查缓冲区是否需要恢复的函数。默认值仅处理访问文件的缓冲区,通过检查文件修改时间实现。不访问文件的缓冲区需要自定义函数,该函数接受一个可选参数 noconfirm。若缓冲区应当被恢复,函数应返回非 nil 值。调用该函数时,当前缓冲区为活跃缓冲区。
该函数主要用于自动恢复,但也可用于其他用途。例如,若未启用自动恢复,它可用于提醒用户缓冲区需要恢复。noconfirm 参数的设计含义是:若缓冲区将直接恢复而不询问用户,则为 t;若函数仅用于提醒用户缓冲区已过期,则为 nil。特别地,在自动恢复场景中,noconfirm 为 t。如果该函数仅用于自动恢复,你可以忽略 noconfirm 参数。
如果你希望每隔 auto-revert-interval 秒就自动执行一次恢复(如同缓冲区菜单),在缓冲区的模式函数中使用如下代码:
(setq-local buffer-stale-function
(lambda (&optional noconfirm) 'fast))
特殊返回值 ‘fast’ 告知调用方:未检查是否需要恢复,但恢复该缓冲区的操作开销很小。它同时告知自动恢复模块不要打印任何恢复信息,即便 auto-revert-verbose 为非 nil。这一点很重要,因为每隔 auto-revert-interval 秒就收到恢复提示会十分扰民。如果该函数被用于自动恢复之外的用途,此返回值提供的信息也可能有用。
当缓冲区具备了合适的 revert-buffer-function 与 buffer-stale-function 后,通常还需要解决若干问题。
缓冲区仅在标记为未修改时才会自动恢复。因此,你必须确保相关函数仅在以下情况将缓冲区标记为已修改:缓冲区包含可能因恢复而丢失的信息,或有理由认为用户正在编辑缓冲区,自动恢复会对其造成干扰。用户始终可以手动调整缓冲区的修改状态来覆盖这一行为。为支持该逻辑,对标记为未修改的缓冲区调用 revert-buffer-function 后,应保持缓冲区标记为未修改。
必须确保光标不会因自动恢复而频繁跳动。当然,如果缓冲区内容发生大幅变化,光标移动可能无法避免。
你应当确保 revert-buffer-function 不会打印与自动恢复模块自身重复的冗余信息(自动恢复的信息在 auto-revert-verbose 为 t 时显示),也不应实际覆盖 auto-revert-verbose 为 nil 的效果。因此,适配模式以支持自动恢复通常需要移除这类消息。对于每隔 auto-revert-interval 秒自动恢复一次的缓冲区,这一点尤为重要。
如果新增的自动恢复功能被集成到 Emacs 中,你应当在 global-auto-revert-non-file-buffers 的文档字符串中加以说明。
同样,你也应当在 Emacs 手册中记录这些新增内容。
缓冲区(buffer)是一种用于存放待编辑文本的 Lisp 对象。缓冲区用于保存已访问文件的内容;同时也存在不关联任何文件的缓冲区。同一时刻可以存在多个缓冲区,但任何时候都只有一个缓冲区被指定为当前缓冲区(current buffer)。大多数编辑命令都作用于当前缓冲区的内容。每个缓冲区(包括当前缓冲区)可以显示在某个窗口中,也可以不显示在任何窗口。
缓冲区(buffer)是一种用于存放待编辑文本的 Lisp 对象。缓冲区用于保存已访问文件的内容;同时也存在不关联任何文件的缓冲区。虽然通常会同时存在多个缓冲区,但任何时刻都只有一个缓冲区被指定为当前缓冲区(current buffer)。大多数编辑命令都作用于当前缓冲区的内容。每个缓冲区(包括当前缓冲区)可以显示在某个窗口中,也可以不显示在任何窗口。
Emacs 编辑中的缓冲区是具有独立名称、并可编辑文本的对象。对 Lisp 程序而言,缓冲区是一种特殊数据类型。你可以将缓冲区内容看作一个可扩展的字符串;插入与删除操作可以发生在缓冲区的任意位置。See Text。
Lisp 缓冲区对象包含大量信息。其中部分信息程序员可通过变量直接访问,另一部分信息则仅能通过专用函数访问。例如,已访问文件名可通过变量直接获取,而光标位置(point)的值仅能通过原始函数获取。
可直接访问的缓冲区专属信息存储在缓冲区局部(buffer-local)变量绑定中,这类变量值仅在特定缓冲区中生效。该特性允许每个缓冲区覆盖特定变量的值。大多数主模式都会以这种方式覆盖 fill-column 或 comment-column 等变量。关于缓冲区局部变量及相关函数的更多信息,参见缓冲区局部变量。
与在缓冲区中访问文件相关的函数和变量,参见访问文件 和 保存缓冲区。与在窗口中显示缓冲区相关的函数和变量,参见Buffers and Windows。
若 object 为缓冲区,该函数返回 t,否则返回 nil。
There are, in general, many buffers in an Emacs session. At any time, one of them is designated the current buffer—the buffer in which most editing takes place. Most of the primitives for examining or changing text operate implicitly on the current buffer (see Text).
Normally, the buffer displayed in the selected window
(see Selecting Windows) is the current buffer, but this is not
always so: a Lisp program can temporarily designate any buffer as
current in order to operate on its contents, without changing what is
displayed on the screen. The most basic function for designating a
current buffer is set-buffer.
This function returns the current buffer.
(current-buffer)
⇒ #<buffer buffers.texi>
This function makes buffer-or-name the current buffer. buffer-or-name must be an existing buffer or the name of an existing buffer. The return value is the buffer made current.
This function does not display the buffer in any window, so the user cannot necessarily see the buffer. But Lisp programs will now operate on it.
When an editing command returns to the editor command loop, Emacs
automatically calls set-buffer on the buffer shown in the
selected window (see Selecting Windows). This is to prevent
confusion: it ensures that the buffer that the cursor is in, when Emacs
reads a command, is the buffer to which that command applies
(see 命令循环). Thus, you should not use set-buffer to
switch visibly to a different buffer; for that, use the functions
described in Switching to a Buffer in a Window.
When writing a Lisp function, do not rely on this behavior of the command loop to restore the current buffer after an operation. Editing commands can also be called as Lisp functions by other programs, not just from the command loop; it is convenient for the caller if the subroutine does not change which buffer is current (unless, of course, that is the subroutine’s purpose).
To operate temporarily on another buffer, put the set-buffer
within a save-current-buffer form. Here, as an example, is a
simplified version of the command append-to-buffer:
(defun append-to-buffer (buffer start end)
"Append the text of the region to BUFFER."
(interactive "BAppend to buffer: \nr")
(let ((oldbuf (current-buffer)))
(save-current-buffer
(set-buffer (get-buffer-create buffer))
(insert-buffer-substring oldbuf start end))))
Here, we bind a local variable to record the current buffer, and then
save-current-buffer arranges to make it current again later.
Next, set-buffer makes the specified buffer current, and
insert-buffer-substring copies the string from the original
buffer to the specified (and now current) buffer.
Alternatively, we can use the with-current-buffer macro:
(defun append-to-buffer (buffer start end)
"Append the text of the region to BUFFER."
(interactive "BAppend to buffer: \nr")
(let ((oldbuf (current-buffer)))
(with-current-buffer (get-buffer-create buffer)
(insert-buffer-substring oldbuf start end))))
In either case, if the buffer appended to happens to be displayed in some window, the next redisplay will show how its text has changed. If it is not displayed in any window, you will not see the change immediately on the screen. The command causes the buffer to become current temporarily, but does not cause it to be displayed.
If you make local bindings (with let or function arguments)
for a variable that may also have buffer-local bindings, make sure
that the same buffer is current at the beginning and at the end of the
local binding’s scope. Otherwise you might bind it in one buffer and
unbind it in another!
Do not rely on using set-buffer to change the current buffer
back, because that won’t do the job if a quit happens while the wrong
buffer is current. For instance, in the previous example, it would
have been wrong to do this:
(let ((oldbuf (current-buffer)))
(set-buffer (get-buffer-create buffer))
(insert-buffer-substring oldbuf start end)
(set-buffer oldbuf))
Using save-current-buffer or with-current-buffer, as we
did, correctly handles quitting, errors, and throw, as well as
ordinary evaluation.
The save-current-buffer special form saves the identity of the
current buffer, evaluates the body forms, and finally restores
that buffer as current. The return value is the value of the last
form in body. The current buffer is restored even in case of an
abnormal exit via throw or error (see 非局部退出).
If the buffer that used to be current has been killed by the time of
exit from save-current-buffer, then it is not made current again,
of course. Instead, whichever buffer was current just before exit
remains current.
The with-current-buffer macro saves the identity of the current
buffer, makes buffer-or-name current, evaluates the body
forms, and finally restores the current buffer. buffer-or-name
must specify an existing buffer or the name of an existing buffer.
The return value is the value of the last form in body. The
current buffer is restored even in case of an abnormal exit via
throw or error (see 非局部退出).
The with-temp-buffer macro evaluates the body forms with
a temporary buffer as the current buffer. It saves the identity of
the current buffer, creates a temporary buffer and makes it current,
evaluates the body forms, and finally restores the previous
current buffer while killing the temporary buffer.
By default, undo information (see Undo) is not recorded in the
buffer created by this macro (but body can enable that, if
needed). The temporary buffer also does not run the hooks
kill-buffer-hook, kill-buffer-query-functions
(see Killing Buffers), and buffer-list-update-hook
(see The Buffer List).
The return value is the value of the last form in body. You can
return the contents of the temporary buffer by using
(buffer-string) as the last form.
The current buffer is restored even in case of an abnormal exit via
throw or error (see 非局部退出).
See also with-temp-file in Writing to Files.
Each buffer has a unique name, which is a string. Many of the functions that work on buffers accept either a buffer or a buffer name as an argument. Any argument called buffer-or-name is of this sort, and an error is signaled if it is neither a string nor a buffer. Any argument called buffer must be an actual buffer object, not a name.
Buffers that are ephemeral and generally uninteresting to the user
have names starting with a space, so that the list-buffers and
buffer-menu commands don’t mention them (but if such a buffer
visits a file, it is mentioned). A name starting with
space also initially disables recording undo information; see
Undo.
This function returns the name of buffer as a string. buffer defaults to the current buffer.
If buffer-name returns nil, it means that buffer
has been killed. See Killing Buffers.
(buffer-name)
⇒ "buffers.texi"
(setq foo (get-buffer "temp"))
⇒ #<buffer temp>
(kill-buffer foo)
⇒ nil
(buffer-name foo)
⇒ nil
foo
⇒ #<killed buffer>
This function renames the current buffer to newname. An error is signaled if newname is not a string.
Ordinarily, rename-buffer signals an error if newname is
already in use. However, if unique is non-nil, it modifies
newname to make a name that is not in use. Interactively, you can
make unique non-nil with a numeric prefix argument.
(This is how the command rename-uniquely is implemented.)
This function returns the name actually given to the buffer.
This function returns the buffer specified by buffer-or-name.
If buffer-or-name is a string and there is no buffer with that
name, the value is nil. If buffer-or-name is a buffer, it
is returned as given; that is not very useful, so the argument is usually
a name. For example:
(setq b (get-buffer "lewis"))
⇒ #<buffer lewis>
(get-buffer b)
⇒ #<buffer lewis>
(get-buffer "Frazzle-nots")
⇒ nil
See also the function get-buffer-create in Creating Buffers.
This function returns a name that would be unique for a new buffer—but does not create the buffer. It starts with starting-name, and produces a name not currently in use for any buffer by appending a number inside of ‘<…>’. It starts at 2 and keeps incrementing the number until it is not the name of an existing buffer.
If the optional second argument ignore is non-nil, it
should be a string, a potential buffer name. It means to consider
that potential buffer acceptable, if it is tried, even if it is the
name of an existing buffer (which would normally be rejected). Thus,
if buffers named ‘foo’, ‘foo<2>’, ‘foo<3>’ and
‘foo<4>’ exist,
(generate-new-buffer-name "foo")
⇒ "foo<5>"
(generate-new-buffer-name "foo" "foo<3>")
⇒ "foo<3>"
(generate-new-buffer-name "foo" "foo<6>")
⇒ "foo<5>"
See the related function generate-new-buffer in Creating Buffers.
This function returns the previous name of buffer, before it was killed or before the last time it was renamed. If nil or omitted, buffer defaults to the current buffer.
The buffer file name is the name of the file that is visited in
that buffer. When a buffer is not visiting a file, its buffer file name
is nil. Most of the time, the buffer name is the same as the
nondirectory part of the buffer file name, but the buffer file name and
the buffer name are distinct and can be set independently.
See 访问文件.
This function returns the absolute file name of the file that
buffer is visiting. If buffer is not visiting any file,
buffer-file-name returns nil. If buffer is not
supplied, it defaults to the current buffer.
(buffer-file-name (other-buffer))
⇒ "/usr/user/lewis/manual/files.texi"
This buffer-local variable contains the name of the file being visited
in the current buffer, or nil if it is not visiting a file. It
is a permanent local variable, unaffected by
kill-all-local-variables.
buffer-file-name
⇒ "/usr/user/lewis/manual/buffers.texi"
It is risky to change this variable’s value without doing various other
things. Normally it is better to use set-visited-file-name (see
below); some of the things done there, such as changing the buffer name,
are not strictly necessary, but others are essential to avoid confusing
Emacs.
This buffer-local variable holds the abbreviated truename of the file
visited in the current buffer, or nil if no file is visited.
It is a permanent local, unaffected by
kill-all-local-variables. See 真实路径, and
abbreviate-file-name.
This buffer-local variable holds the inode number and device
identifier of the file visited in the current buffer, or nil if no
file or a nonexistent file is visited. It is a permanent local,
unaffected by kill-all-local-variables.
The value is normally a list of the form (inodenum
device). This tuple uniquely identifies the file among
all files accessible on the system. See the function
file-attributes, in 文件属性, for more information
about them.
If buffer-file-name is the name of a symbolic link, then both
inodenum and device refer to the recursive target of the link.
This function returns the buffer visiting file filename. If
there is no such buffer, it returns nil. The argument
filename, which must be a string, is expanded (see 文件名展开相关函数), then compared against the visited file names of all live
buffers. Note that the buffer’s buffer-file-name must match
the expansion of filename exactly. This function will not
recognize other names for the same file.
(get-file-buffer "buffers.texi")
⇒ #<buffer buffers.texi>
In unusual circumstances, there can be more than one buffer visiting the same file name. In such cases, this function returns the first such buffer in the buffer list.
This is like get-file-buffer, except that it can return any
buffer visiting the file possibly under a different name. That
is, the buffer’s buffer-file-name does not need to match the
expansion of filename exactly, it only needs to refer to the
same file. If predicate is non-nil, it should be a
function of one argument, a buffer visiting filename. The
buffer is only considered a suitable return value if predicate
returns non-nil. If it can not find a suitable buffer to
return, find-buffer-visiting returns nil.
If filename is a non-empty string, this function changes the name of the file visited in the current buffer to filename. (If the buffer had no visited file, this gives it one.) The next time the buffer is saved it will go in the newly-specified file.
This command marks the buffer as modified, since it does not (as far as Emacs knows) match the contents of filename, even if it matched the former visited file. It also renames the buffer to correspond to the new file name, unless the new name is already in use.
If filename is nil or the empty string, that stands for
“no visited file”. In this case, set-visited-file-name marks
the buffer as having no visited file, without changing the buffer’s
modified flag.
Normally, this function asks the user for confirmation if there
already is a buffer visiting filename. If no-query is
non-nil, that prevents asking this question. If there already
is a buffer visiting filename, and the user confirms or
no-query is non-nil, this function makes the new
buffer name unique by appending a number inside of ‘<…>’ to
filename.
If along-with-file is non-nil, that means to assume that
the former visited file has been renamed to filename. In this
case, the command does not change the buffer’s modified flag, nor the
buffer’s recorded last file modification time as reported by
visited-file-modtime (see Buffer Modification Time). If
along-with-file is nil, this function clears the recorded
last file modification time, after which visited-file-modtime
returns zero.
When the function set-visited-file-name is called
interactively, it prompts for filename in the minibuffer.
This buffer-local variable specifies a string to display in a buffer listing where the visited file name would go, for buffers that don’t have a visited file name. Dired buffers use this variable.
Emacs keeps a flag called the modified flag for each buffer, to
record whether you have changed the text of the buffer. This flag is
set to t whenever you alter the contents of the buffer, and
cleared to nil when you save it. Thus, the flag shows whether
there are unsaved changes. The flag value is normally shown in the mode
line (see 模式行中使用的变量), and controls saving (see 保存缓冲区) and auto-saving (see 自动保存).
Some Lisp programs set the flag explicitly. For example, the function
set-visited-file-name sets the flag to t, because the text
does not match the newly-visited file, even if it is unchanged from the
file formerly visited.
The functions that modify the contents of buffers are described in Text.
This function returns non-nil if buffer has
been modified since it was last read in from a file or saved, or
nil otherwise. If buffer has been auto-saved since the
time it was last modified, this function returns the symbol
autosaved. If buffer is nil or omitted, it
defaults to the current buffer.
This function marks the current buffer as modified if flag is
non-nil, or as unmodified if the flag is nil.
Another effect of calling this function is to cause unconditional
redisplay of the mode line for the current buffer. In fact, the
function force-mode-line-update works by doing this:
(set-buffer-modified-p (buffer-modified-p))
Like set-buffer-modified-p, but does not force redisplay of
mode lines. This function also allows flag’s value to be
the symbol autosaved, which marks the buffer as modified and
auto-saved after the last modification.
This command marks the current buffer as unmodified, and not needing
to be saved. If arg is non-nil, it marks the buffer as
modified, so that it will be saved at the next suitable occasion.
Interactively, arg is the prefix argument.
Don’t use this function in programs, since it prints a message in the
echo area; use set-buffer-modified-p (above) instead.
This function returns buffer’s modification-count. This is a
counter that increments every time the buffer is modified. If
buffer is nil (or omitted), the current buffer is used.
This function returns buffer’s character-change modification-count.
Changes to text properties leave this counter unchanged; however, each
time text is inserted or removed from the buffer, the counter is reset
to the value that would be returned by buffer-modified-tick.
By comparing the values returned by two buffer-chars-modified-tick
calls, you can tell whether a character change occurred in that buffer
in between the calls. If buffer is nil (or omitted), the
current buffer is used.
Sometimes there’s a need for modifying buffer in a way that doesn’t
really change its text, like if only its text properties are changed.
If your program needs to modify a buffer without triggering any hooks
and features that react to buffer modifications, use the
with-silent-modifications macro.
Execute body pretending it does not modify the buffer. This includes checking whether the buffer’s file is locked (see 文件锁), running buffer modification hooks (see Change Hooks), etc. Note that if body actually modifies the buffer text (as opposed to its text properties), its undo data may become corrupted.
Suppose that you visit a file and make changes in its buffer, and meanwhile the file itself is changed on disk. At this point, saving the buffer would overwrite the changes in the file. Occasionally this may be what you want, but usually it would lose valuable information. Emacs therefore checks the file’s modification time using the functions described below before saving the file. (See 文件属性, for how to examine a file’s modification time.)
This function compares what buffer (by default, the current-buffer) has recorded for the modification time of its visited file against the actual modification time of the file as recorded by the operating system. The two should be the same unless some other process has written the file since Emacs visited or saved it.
The function returns t if the last actual modification time and
Emacs’s recorded modification time are the same, nil otherwise.
It also returns t if the buffer has no recorded last
modification time, that is if visited-file-modtime would return
zero.
It always returns t for buffers that are not visiting a file,
even if visited-file-modtime returns a non-zero value. For
instance, it always returns t for dired buffers. It returns
t for buffers that are visiting a file that does not exist and
never existed, but nil for file-visiting buffers whose file has
been deleted.
This function clears out the record of the last modification time of the file being visited by the current buffer. As a result, the next attempt to save this buffer will not complain of a discrepancy in file modification times.
This function is called in set-visited-file-name and other
exceptional places where the usual test to avoid overwriting a changed
file should not be done.
This function returns the current buffer’s recorded last file modification time, as a Lisp timestamp (see Time of Day).
If the buffer has no recorded last modification time, this function
returns zero. This case occurs, for instance, if the buffer is not
visiting a file or if the time has been explicitly cleared by
clear-visited-file-modtime. Note, however, that
visited-file-modtime returns a timestamp for some non-file buffers
too. For instance, in a Dired buffer listing a directory, it returns
the last modification time of that directory, as recorded by Dired.
If the buffer is visiting a file that doesn’t exist, this function returns −1.
This function updates the buffer’s record of the last modification time
of the visited file, to the value specified by time if time
is not nil, and otherwise to the last modification time of the
visited file.
If time is neither nil nor an integer flag returned
by visited-file-modtime, it should be a Lisp time value
(see Time of Day).
This function is useful if the buffer was not read from the file normally, or if the file itself has been changed for some known benign reason.
This function is used to ask a user how to proceed after an attempt to modify a buffer visiting file filename when the file is newer than the buffer text. Emacs detects this because the modification time of the file on disk is newer than the last save-time and its contents have changed. This means some other program has probably altered the file.
Depending on the user’s answer, the function may return normally, in
which case the modification of the buffer proceeds, or it may signal a
file-supersession error with data (filename), in which
case the proposed buffer modification is not allowed.
This function is called automatically by Emacs on the proper occasions. It exists so you can customize Emacs by redefining it. See the file userlock.el for the standard definition.
See also the file locking mechanism in 文件锁.
If a buffer is read-only, then you cannot change its contents, although you may change your view of the contents by scrolling and narrowing.
Read-only buffers are used in two kinds of situations:
Here, the purpose is to inform the user that editing the buffer with the aim of saving it in the file may be futile or undesirable. The user who wants to change the buffer text despite this can do so after clearing the read-only flag with C-x C-q.
The special commands of these modes bind buffer-read-only to
nil (with let) or bind inhibit-read-only to
t around the places where they themselves change the text.
This buffer-local variable specifies whether the buffer is read-only.
The buffer is read-only if this variable is non-nil. However,
characters that have the inhibit-read-only text property can
still be modified. See inhibit-read-only.
If this variable is non-nil, then read-only buffers and,
depending on the actual value, some or all read-only characters may be
modified. Read-only characters in a buffer are those that have a
non-nil read-only text property. See Properties with Special Meanings, for more information about text properties.
If inhibit-read-only is t, all read-only character
properties have no effect. If inhibit-read-only is a list, then
read-only character properties have no effect if they are members
of the list (comparison is done with eq).
This is the mode command for Read Only minor mode, a buffer-local
minor mode. When the mode is enabled, buffer-read-only is
non-nil in the buffer; when disabled, buffer-read-only
is nil in the buffer. The calling convention is the same as
for other minor mode commands (see 编写次要模式的规范).
This minor mode mainly serves as a wrapper for
buffer-read-only; unlike most minor modes, there is no separate
read-only-mode variable. Even when Read Only mode is disabled,
characters with non-nil read-only text properties remain
read-only. To temporarily ignore all read-only states, bind
inhibit-read-only, as described above.
When enabling Read Only mode, this mode command also enables View mode
if the option view-read-only is non-nil. See Miscellaneous Buffer Operations in The GNU Emacs Manual.
When disabling Read Only mode, it disables View mode if View mode was
enabled.
This function signals a buffer-read-only error if the current
buffer is read-only. If the text at position (which defaults to
point) has the inhibit-read-only text property set, the error
will not be raised.
See 使用 interactive, for another way to signal an error if the
current buffer is read-only.
The buffer list is a list of all live buffers. The order of the
buffers in this list is based primarily on how recently each buffer has
been displayed in a window. Several functions, notably
other-buffer, use this ordering. A buffer list displayed for the
user also follows this order.
Creating a buffer adds it to the end of the buffer list, and killing
a buffer removes it from that list. A buffer moves to the front of
this list whenever it is chosen for display in a window
(see Switching to a Buffer in a Window) or a window displaying it is selected
(see Selecting Windows). A buffer moves to the end of the list
when it is buried (see bury-buffer, below). There are no
functions available to the Lisp programmer which directly manipulate
the buffer list.
In addition to the fundamental buffer list just described, Emacs
maintains a local buffer list for each frame, in which the buffers that
have been displayed (or had their windows selected) in that frame come
first. (This order is recorded in the frame’s buffer-list frame
parameter; see Buffer Parameters.) Buffers never displayed in
that frame come afterward, ordered according to the fundamental buffer
list.
This function returns the buffer list, including all buffers, even those whose names begin with a space. The elements are actual buffers, not their names.
If frame is a frame, this returns frame’s local buffer list.
If frame is nil or omitted, the fundamental buffer list is
used: the buffers appear in order of most recent display or selection,
regardless of which frames they were displayed on.
(buffer-list)
⇒ (#<buffer buffers.texi>
#<buffer *Minibuf-1*> #<buffer buffer.c>
#<buffer *Help*> #<buffer TAGS>)
;; Note that the name of the minibuffer ;; begins with a space! (mapcar #'buffer-name (buffer-list)) ⇒ ("buffers.texi" " *Minibuf-1*" "buffer.c" "*Help*" "TAGS")
The list returned by buffer-list is constructed specifically;
it is not an internal Emacs data structure, and modifying it has no
effect on the order of buffers. If you want to change the order of
buffers in the fundamental buffer list, here is an easy way:
(defun reorder-buffer-list (new-list)
(while new-list
(bury-buffer (car new-list))
(setq new-list (cdr new-list))))
With this method, you can specify any order for the list, but there is no danger of losing a buffer or adding something that is not a valid live buffer.
To change the order or value of a specific frame’s buffer list, set
that frame’s buffer-list parameter with
modify-frame-parameters (see Access to Frame Parameters).
This function returns the first buffer in the buffer list other than buffer. Usually, this is the buffer appearing in the most recently selected window (in frame frame or else the selected frame, see Input Focus), aside from buffer. Buffers whose names start with a space are not considered at all.
If buffer is not supplied (or if it is not a live buffer), then
other-buffer returns the first buffer in the selected frame’s
local buffer list. (If frame is non-nil, it returns the
first buffer in frame’s local buffer list instead.)
If frame has a non-nil buffer-predicate parameter,
then other-buffer uses that predicate to decide which buffers to
consider. It calls the predicate once for each buffer, and if the value
is nil, that buffer is ignored. See Buffer Parameters.
If visible-ok is nil, other-buffer avoids returning
a buffer visible in any window on any visible frame, except as a last
resort. If visible-ok is non-nil, then it does not matter
whether a buffer is displayed somewhere or not.
If no suitable buffer exists, the buffer *scratch* is returned (and created, if necessary).
This function returns the last buffer in frame’s buffer list other
than buffer. If frame is omitted or nil, it uses the
selected frame’s buffer list.
The argument visible-ok is handled as with other-buffer,
see above. If no suitable buffer can be found, the buffer
*scratch* is returned.
This command puts buffer-or-name at the end of the buffer list,
without changing the order of any of the other buffers on the list.
This buffer therefore becomes the least desirable candidate for
other-buffer to return. The argument can be either a buffer
itself or the name of one.
This function operates on each frame’s buffer-list parameter as
well as the fundamental buffer list; therefore, the buffer that you bury
will come last in the value of (buffer-list frame) and in
the value of (buffer-list). In addition, it also puts the buffer
at the end of the list of buffers of the selected window (see Window History) provided it is shown in that window.
If buffer-or-name is nil or omitted, this means to bury the
current buffer. In addition, if the current buffer is displayed in the
selected window (see Selecting Windows), this makes sure that the
window is either deleted or another buffer is shown in it. More
precisely, if the selected window is dedicated (see Dedicated Windows) and there are other windows on its frame, the window is
deleted. If it is the only window on its frame and that frame is not
the only frame on its terminal, the frame is dismissed by calling the
function specified by frame-auto-hide-function (see Quitting Windows). Otherwise, it calls switch-to-prev-buffer
(see Window History) to show another buffer in that window. If
buffer-or-name is displayed in some other window, it remains
displayed there.
To replace a buffer in all the windows that display it, use
replace-buffer-in-windows, See Buffers and Windows.
This command switches to the last buffer in the local buffer list of
the selected frame. More precisely, it calls the function
switch-to-buffer (see Switching to a Buffer in a Window), to display the
buffer returned by last-buffer (see above), in the selected
window.
This is a normal hook run whenever the buffer list changes. Functions
(implicitly) running this hook are get-buffer-create
(see Creating Buffers), rename-buffer (see Buffer Names), kill-buffer (see Killing Buffers),
bury-buffer (see above), and select-window
(see Selecting Windows). This hook is not run for internal or
temporary buffers created by get-buffer-create or
generate-new-buffer with a non-nil argument
inhibit-buffer-hooks.
Functions run by this hook should avoid calling select-window
with a nil norecord argument since this may lead to
infinite recursion.
This function checks if a buffer designated by buffer-or-name
satisfies the specified condition. Optional arguments
args are passed to the predicate function in condition. A
valid condition can be one of the following:
nil if the buffer
matches. It is called with
buffer-or-name as the first argument followed by args.
(oper . expr) where oper is one
of
(not cond)Satisfied if cond doesn’t satisfy buffer-match-p with
the same buffer and args.
(or conds…)Satisfied if any condition in conds satisfies
buffer-match-p, with the same buffer and args.
(and conds…)Satisfied if all the conditions in conds satisfy
buffer-match-p, with the same buffer and args.
derived-modeSatisfied if the buffer’s major mode derives from expr. Note
that this condition might fail to report a match if
buffer-match-p is invoked before the major mode of the buffer
has been established.
major-modeSatisfied if the buffer’s major mode is equal to expr. Prefer
using derived-mode instead, when both can work. Note that this
condition might fail to report a match if buffer-match-p is
invoked before the major mode of the buffer has been established.
categoryThis is pertinent only when this function is called by
display-buffer (see Action Alists for Buffer Display), and is
satisfied if the action alist with which display-buffer was
called includes (category . expr) in the value of its
action argument. See Action Alists for Buffer Display.
"" (empty
string) or (and) (empty conjunction).
This function returns a list of all buffers that satisfy the
condition. If no buffers match, the function returns
nil. The argument condition is as defined in
buffer-match-p above. By default, all the buffers are
considered, but this can be restricted via the optional argument
buffer-list, which should be a list of buffers to consider.
Remaining arguments args will be passed to condition in
the same way as buffer-match-p does.
This section describes the two primitives for creating buffers.
get-buffer-create creates a buffer if it finds no existing
buffer with the specified name; generate-new-buffer always
creates a new buffer and gives it a unique name.
Both functions accept an optional argument inhibit-buffer-hooks.
If it is non-nil, the buffer they create does not run the hooks
kill-buffer-hook, kill-buffer-query-functions
(see Killing Buffers), and buffer-list-update-hook
(see The Buffer List). This avoids slowing down internal or temporary
buffers that are never presented to users or passed on to other
applications.
Other functions you can use to create buffers include
with-output-to-temp-buffer (see Temporary Displays) and
create-file-buffer (see 访问文件). Starting a
subprocess can also create a buffer (see Processes).
This function returns a buffer named buffer-or-name. The buffer returned does not become the current buffer—this function does not change which buffer is current.
buffer-or-name must be either a string or an existing buffer. If
it is a string and a live buffer with that name already exists,
get-buffer-create returns that buffer. If no such buffer exists,
it creates a new buffer. If buffer-or-name is a buffer instead of
a string, it is returned as given, even if it is dead.
(get-buffer-create "foo")
⇒ #<buffer foo>
The major mode for a newly created buffer is set to Fundamental mode.
(The default value of the variable major-mode is handled at a higher
level; see Emacs 如何选择主模式.) If the name begins with a space, the
buffer initially disables undo information recording (see Undo).
This function returns a newly created, empty buffer, but does not make
it current. The name of the buffer is generated by passing name
to the function generate-new-buffer-name (see Buffer Names). Thus, if there is no buffer named name, then that is
the name of the new buffer; if that name is in use, a suffix of the
form ‘<n>’, where n is an integer, is appended to
name.
An error is signaled if name is not a string.
(generate-new-buffer "bar")
⇒ #<buffer bar>
(generate-new-buffer "bar")
⇒ #<buffer bar<2>>
(generate-new-buffer "bar")
⇒ #<buffer bar<3>>
The major mode for the new buffer is set to Fundamental mode. The default
value of the variable major-mode is handled at a higher level.
See Emacs 如何选择主模式.
Killing a buffer makes its name unknown to Emacs and makes the memory space it occupied available for other use.
The buffer object for the buffer that has been killed remains in
existence as long as anything refers to it, but it is specially marked
so that you cannot make it current or display it. Killed buffers retain
their identity, however; if you kill two distinct buffers, they remain
distinct according to eq although both are dead.
If you kill a buffer that is current or displayed in a window, Emacs automatically selects or displays some other buffer instead. This means that killing a buffer can change the current buffer. Therefore, when you kill a buffer, you should also take the precautions associated with changing the current buffer (unless you happen to know that the buffer being killed isn’t current). See The Current Buffer.
If you kill a buffer that is the base buffer of one or more indirect buffers (see Indirect Buffers), the indirect buffers are automatically killed as well.
The buffer-name of a buffer is nil if, and only if,
the buffer is killed. A buffer that has not been killed is called a
live buffer. To test whether a buffer is live or killed, use
the function buffer-live-p (see below).
This function kills the buffer buffer-or-name, freeing all its
memory for other uses or to be returned to the operating system. If
buffer-or-name is nil or omitted, it kills the current
buffer.
Any processes that have this buffer as the process-buffer are
sent the SIGHUP (hangup) signal, which normally causes them
to terminate. See Sending Signals to Processes.
If the buffer is visiting a file and contains unsaved changes,
kill-buffer asks the user to confirm before the buffer is killed.
It does this even if not called interactively. To prevent the request
for confirmation, clear the modified flag before calling
kill-buffer. See Buffer Modification.
This function calls replace-buffer-in-windows for cleaning up
all windows currently displaying the buffer to be killed.
Killing a buffer that is already dead has no effect.
This function returns t if it actually killed the buffer. It
returns nil if the user refuses to confirm or if
buffer-or-name was already dead.
(kill-buffer "foo.unchanged")
⇒ t
(kill-buffer "foo.changed")
---------- Buffer: Minibuffer ----------
Buffer foo.changed modified; kill anyway? (yes or no) yes
---------- Buffer: Minibuffer ----------
⇒ t
Before confirming unsaved changes, kill-buffer calls the functions
in the list kill-buffer-query-functions, in order of appearance,
with no arguments. The buffer being killed is the current buffer when
they are called. The idea of this feature is that these functions will
ask for confirmation from the user. If any of them returns nil,
kill-buffer spares the buffer’s life.
This hook is not run for internal or temporary buffers created by
get-buffer-create or generate-new-buffer with a
non-nil argument inhibit-buffer-hooks.
This is a normal hook run by kill-buffer after asking all the
questions it is going to ask, just before actually killing the buffer.
The buffer to be killed is current when the hook functions run.
See 钩子. This variable is a permanent local, so its local binding
is not cleared by changing major modes.
This hook is not run for internal or temporary buffers created by
get-buffer-create or generate-new-buffer with a
non-nil argument inhibit-buffer-hooks.
This variable, if non-nil in a particular buffer, tells
save-buffers-kill-emacs to offer to save that buffer, just as
it offers to save file-visiting buffers. If save-some-buffers
is called with the second optional argument set to t, it will
also offer to save the buffer. Lastly, if this variable is set to the
symbol always, both save-buffers-kill-emacs and
save-some-buffers will always offer to save. See Definition of save-some-buffers. The variable buffer-offer-save
automatically becomes buffer-local when set for any reason.
See 缓冲区局部变量.
This variable, if non-nil in a particular buffer, tells
save-buffers-kill-emacs and save-some-buffers to save
this buffer (if it’s modified) without asking the user. The variable
automatically becomes buffer-local when set for any reason.
This function returns t if object is a live buffer (a
buffer which has not been killed), nil otherwise.
An indirect buffer shares the text of some other buffer, which is called the base buffer of the indirect buffer. In some ways it is the analogue, for buffers, of a symbolic link among files. The base buffer may not itself be an indirect buffer.
The text of the indirect buffer is always identical to the text of its base buffer; changes made by editing either one are visible immediately in the other. This includes the text properties as well as the characters themselves.
In all other respects, the indirect buffer and its base buffer are completely separate. They have different names, independent values of point, independent narrowing, independent markers and overlays (though inserting or deleting text in either buffer relocates the markers and overlays for both), independent major modes, and independent buffer-local variable bindings.
An indirect buffer cannot visit a file, but its base buffer can. If you try to save the indirect buffer, that actually saves the base buffer.
Killing an indirect buffer has no effect on its base buffer. Killing the base buffer effectively kills the indirect buffer in that it cannot ever again be the current buffer.
This creates and returns an indirect buffer named name whose base buffer is base-buffer. The argument base-buffer may be a live buffer or the name (a string) of an existing buffer. If name is the name of an existing buffer, an error is signaled.
If clone is non-nil, then the indirect buffer originally
shares the state of base-buffer such as major mode, minor
modes, buffer local variables and so on. If clone is omitted
or nil the indirect buffer’s state is set to the default state
for new buffers.
If base-buffer is an indirect buffer, its base buffer is used as
the base for the new buffer. If, in addition, clone is
non-nil, the initial state is copied from the actual base
buffer, not from base-buffer.
See Creating Buffers, for the meaning of inhibit-buffer-hooks.
This function creates and returns a new indirect buffer that shares the current buffer’s base buffer and copies the rest of the current buffer’s attributes. (If the current buffer is not indirect, it is used as the base buffer.)
If display-flag is non-nil, as it always is in
interactive calls, that means to display the new buffer by calling
pop-to-buffer. If norecord is non-nil, that means
not to put the new buffer to the front of the buffer list.
This function returns the base buffer of buffer, which defaults
to the current buffer. If buffer is not indirect, the value is
nil. Otherwise, the value is another buffer, which is never an
indirect buffer.
Specialized modes sometimes need to let the user access from the same buffer several vastly different types of text. For example, you may need to display a summary of the buffer text, in addition to letting the user access the text itself.
This could be implemented with multiple buffers (kept in sync when the user edits the text), or with narrowing (see Narrowing). But these alternatives might sometimes become tedious or prohibitively expensive, especially if each type of text requires expensive buffer-global operations in order to provide correct display and editing commands.
Emacs provides another facility for such modes: you can quickly swap
buffer text between two buffers with buffer-swap-text. This
function is very fast because it doesn’t move any text, it only
changes the internal data structures of the buffer object to point to
a different chunk of text. Using it, you can pretend that a group of
two or more buffers are actually a single virtual buffer that holds
the contents of all the individual buffers together.
This function swaps the text of the current buffer and that of its argument buffer. It signals an error if one of the two buffers is an indirect buffer (see Indirect Buffers) or is a base buffer of an indirect buffer.
All the buffer properties that are related to the buffer text are
swapped as well: the positions of point and mark, all the markers, the
overlays, the text properties, the undo list, the value of the
enable-multibyte-characters flag (see enable-multibyte-characters), etc.
Warning: If this function is called from within a
save-excursion form, the current buffer will be set to
buffer upon leaving the form, since the marker used by
save-excursion to save the position and buffer will be swapped
as well.
If you use buffer-swap-text on a file-visiting buffer, you
should set up a hook to save the buffer’s original text rather than
what it was swapped with. write-region-annotate-functions
works for this purpose. You should probably set
buffer-saved-size to −2 in the buffer, so that changes
in the text it is swapped with will not interfere with auto-saving.
Emacs buffers are implemented using an invisible gap to make insertion and deletion faster. Insertion works by filling in part of the gap, and deletion adds to the gap. Of course, this means that the gap must first be moved to the locus of the insertion or deletion. Emacs moves the gap only when you try to insert or delete. This is why your first editing command in one part of a large buffer, after previously editing in another far-away part, sometimes involves a noticeable delay.
This mechanism works invisibly, and Lisp code should never be affected by the gap’s current location, but these functions are available for getting information about the gap status.
This function returns the current gap position in the current buffer.
This function returns the current gap size of the current buffer.
This chapter describes the functions and variables related to Emacs windows. See Frames, for how windows are assigned an area of screen available for Emacs to use. See Emacs Display, for information on how text is displayed in windows.
A window is an area of the screen that can be used to display a buffer (see 缓冲区). Windows are grouped into frames (see Frames). Each frame contains at least one window; the user can subdivide a frame into multiple, non-overlapping windows to view several buffers at once. Lisp programs can use multiple windows for a variety of purposes. In Rmail, for example, you can view a summary of message titles in one window, and the contents of the selected message in another window.
Emacs uses the term “window” with a different meaning than in graphical desktop environments and window systems, such as the X Window System. When Emacs is run on X, each graphical X window owned by the Emacs process corresponds to one Emacs frame. When Emacs is run on a text terminal, each Emacs frame fills the entire terminal screen. In either case, the frame may contain one or more Emacs windows. For disambiguation, we use the term window-system window when we mean the window-system window corresponding to an Emacs frame.
Unlike X windows, Emacs windows are tiled; they never overlap within the area of their frame. When a window is created, resized, or deleted, the change in window space is taken from or given to other windows on the same frame, so that the total area of the frame is unchanged.
In Emacs Lisp, windows are represented by a special Lisp object type (see 窗口类型).
This function returns t if object is a window (whether or
not it displays a buffer). Otherwise, it returns nil.
A live window is one that is actually displaying a buffer in a frame.
This function returns t if object is a live window and
nil otherwise. A live window is one that displays a buffer.
The windows in each frame are organized into a window tree. See Windows and Frames. The leaf nodes of each window tree are live windows—the ones actually displaying buffers. The internal nodes of the window tree are internal windows, which are not live.
A valid window is one that is either live or internal. A valid window can be deleted, i.e., removed from its frame (see Deleting Windows); then it is no longer valid, but the Lisp object representing it might be still referenced from other Lisp objects. A deleted window may be made valid again by restoring a saved window configuration (see Window Configurations).
You can distinguish valid windows from deleted windows with
window-valid-p.
This function returns t if object is a live window, or an
internal window in a window tree. Otherwise, it returns nil,
including for the case where object is a deleted window.
The following schematic shows the structure of a live window:
____________________________________________
|________________ Tab Line _______________|RD| ^
|______________ Header Line ______________| | |
^ |LS|LM|LF| |RF|RM|RS| | |
| | | | | | | | | | |
Window | | | | | | | | | Window
Body | | | | | Window Body | | | | | Total
Height | | | | | | | | | Height
| | | | |<- Window Body Width ->| | | | | |
v |__|__|__|_______________________|__|__|__| | |
|_________ Horizontal Scroll Bar _________| | |
|_______________ Mode Line _______________|__| |
|_____________ Bottom Divider _______________| v
<---------- Window Total Width ------------>
At the center of that window is the body, where the buffer text is displayed. The body can be surrounded by a series of optional areas which we will call window decorations. On the left and right, from innermost to outermost, these are the left and right fringes, denoted by LF and RF (see Fringes); the left and right margins, denoted by LM and RM in the schematic (see Displaying in the Margins); the left or right vertical scroll bar, only one of which is present at any time, denoted by LS and RS (see Scroll Bars); and the right divider, denoted by RD (see Window Dividers). Together these are the window’s left and right decorations.
At the top of the window are the tab line and the header line (see 窗口标题栏). The text area of the window includes the header line and the tab line, if they are present in the window. At the bottom of the window are the horizontal scroll bar (see Scroll Bars); the mode line (see 模式行格式); and the bottom divider (see Window Dividers). Together these form the window’s top and bottom decorations.
There are two special areas omitted in the schematic:
In either case, the resulting artifact is considered part of the window’s body although its screen space cannot be used for displaying buffer text.
Note also, that line numbers (and their surrounding whitespace) as
displayed by display-line-numbers-mode (see Display Custom in The GNU Emacs Manual) do not count as decorations either; they
are part of the window’s body too.
Internal windows neither show any text nor do they have decorations. Hence, the concept of “body” does not make sense for them. In fact, most functions operating on the body of a window will yield an error when applied to an internal window.
By default, an Emacs frame exhibits one special live window that is used for displaying messages and accepting user input—the minibuffer window (see Minibuffer 窗口). Since the minibuffer window is used for displaying text, it has a body but it does not have a tab or header line or any margins. Finally, a tooltip window which is used for displaying a tooltip in a tooltip frame (see Tooltips) has a body too but no decorations at all.
Each window belongs to exactly one frame (see Frames). For all windows belonging to a specific frame, we sometimes also say that these windows are owned by that frame or simply that they are on that frame.
This function returns the specified window’s frame—the frame
that window belongs to. If window is omitted or nil,
it defaults to the selected window (see Selecting Windows).
This function returns a list of all live windows owned by the specified
frame. If frame is omitted or nil, it defaults to
the selected frame (see Input Focus).
The optional argument minibuffer specifies whether to include the
minibuffer window (see Minibuffer 窗口) in that list. If
minibuffer is t, the minibuffer window is included. If
nil or omitted, the minibuffer window is included only if it is
active. If minibuffer is neither nil nor t, the
minibuffer window is never included.
The optional argument window, if non-nil, must be a live
window on the specified frame; then window will be the first
element in the returned list. If window is omitted or nil,
the window selected within frame (see Selecting Windows) is
the first element.
Windows on the same frame are organized into a window tree, whose leaf nodes are the live windows. The internal nodes of a window tree are not live; they exist for the purpose of organizing the relationships between live windows. The root node of a window tree is called the root window. It is either a live window or an internal window. If it is a live window, then the frame has just one window besides the minibuffer window, or the frame is a minibuffer-only frame, see Frame Layout.
A minibuffer window (see Minibuffer 窗口) that is not alone on
its frame does not have a parent window, so it strictly speaking is not
part of its frame’s window tree. Nonetheless, it is a sibling window of
the frame’s root window, and thus can be reached from the root window via
window-next-sibling, see below. Also, the function
window-tree described at the end of this section lists the
minibuffer window alongside the actual window tree.
This function returns the root window for frame-or-window. The
argument frame-or-window should be either a window or a frame;
if omitted or nil, it defaults to the selected frame. If
frame-or-window is a window, the return value is the root window
of that window’s frame.
When a live window is split (see Splitting Windows), there are two live windows where previously there was one. One of these is represented by the same Lisp window object as the original window, and the other is represented by a newly-created Lisp window object. Both of these live windows become leaf nodes of the window tree, as child windows of a single internal window. If necessary, Emacs automatically creates this internal window, which is also called the parent window, and assigns it to the appropriate position in the window tree. The set of windows that share the same parent are called siblings.
This function returns the parent window of window. If
window is omitted or nil, it defaults to the selected
window. The return value is nil if window has no parent
(i.e., it is a minibuffer window or the root window of its frame).
A parent window always has at least two child windows. If this number were to fall to one as a result of window deletion (see Deleting Windows), Emacs automatically deletes the parent window too, and its sole remaining child window takes its place in the window tree.
A child window can be either a live window, or an internal window (which in turn would have its own child windows). Therefore, each internal window can be thought of as occupying a certain rectangular screen area—the union of the areas occupied by the live windows that are ultimately descended from it.
For each internal window, the screen areas of the immediate children are arranged either vertically or horizontally (never both). If the child windows are arranged one above the other, they are said to form a vertical combination; if they are arranged side by side, they are said to form a horizontal combination. Consider the following example:
______________________________________
| ______ ____________________________ |
|| || __________________________ ||
|| ||| |||
|| ||| |||
|| ||| |||
|| |||____________W4____________|||
|| || __________________________ ||
|| ||| |||
|| ||| |||
|| |||____________W5____________|||
||__W2__||_____________W3_____________ |
|__________________W1__________________|
The root window of this frame is an internal window, W1. Its child windows form a horizontal combination, consisting of the live window W2 and the internal window W3. The child windows of W3 form a vertical combination, consisting of the live windows W4 and W5. Hence, the live windows in this window tree are W2, W4, and W5.
The following functions can be used to retrieve a child window of an internal window, and the siblings of a child window. Their window argument always defaults to the selected window (see Selecting Windows).
This function returns the topmost child window of window, if
window is an internal window whose children form a vertical
combination. For any other type of window, the return value is
nil.
This function returns the leftmost child window of window, if
window is an internal window whose children form a horizontal
combination. For any other type of window, the return value is
nil.
This function returns the first child window of the internal window
window—the topmost child window for a vertical combination, or
the leftmost child window for a horizontal combination. If
window is a live window, the return value is nil.
This function returns a non-nil value if and only if
window is part of a vertical combination.
If the optional argument horizontal is non-nil, this
means to return non-nil if and only if window is part of
a horizontal combination.
This function returns the next sibling of the specified window. The
return value is nil if window is the last child of its
parent.
This function returns the previous sibling of the specified window.
The return value is nil if window is the first child of its
parent.
The functions window-next-sibling and window-prev-sibling
should not be confused with the functions next-window and
previous-window, which return the next and previous window in the
cyclic ordering of windows (see Cyclic Ordering of Windows).
The following functions can be useful to locate a window within its frame.
This function returns the live window at the upper left corner of the
frame specified by frame-or-window. The argument
frame-or-window must denote a window or a live frame and defaults
to the selected frame. If frame-or-window specifies a window,
this function returns the first window on that window’s frame. Under
the assumption that the frame from our canonical example is selected
(frame-first-window) returns W2.
This function returns t if window is located at
side of its containing frame. The argument window must be
a valid window and defaults to the selected one. The argument
side can be any of the symbols left, top,
right or bottom. The default value nil is
handled like bottom.
Note that this function disregards the minibuffer window
(see Minibuffer 窗口). Hence, with side equal to
bottom it may return t also when the minibuffer window
appears right below window.
This function returns the nearest live window in direction
direction as seen from the position of window-point in
window window. The argument direction must be one of
above, below, left or right. The optional
argument window must denote a live window and defaults to the
selected one.
This function does not return a window whose no-other-window
parameter is non-nil (see Window Parameters). If the nearest
window’s no-other-window parameter is non-nil, this
function tries to find another window in the indicated direction whose
no-other-window parameter is nil. If the optional
argument ignore is non-nil, a window may be returned even
if its no-other-window parameter is non-nil.
If the optional argument sign is a negative number, it means to
use the right or bottom edge of window as reference position
instead of window-point. If sign is a positive number, it
means to use the left or top edge of window as reference position.
If the optional argument wrap is non-nil, this means to
wrap direction around frame borders. For example, if window
is at the top of the frame and direction is above, then
this function usually returns the frame’s minibuffer window if it’s
active and a window at the bottom of the frame otherwise.
If the optional argument minibuf is t, this function may
return the minibuffer window even when it’s not active. If the
optional argument minibuf is nil, this means to return
the minibuffer window if and only if it is currently active.
If minibuf is neither nil nor t, this function
never returns the minibuffer window. However, if wrap is
non-nil, it always acts as if minibuf were nil.
If it doesn’t find a suitable window, this function returns
nil.
Don’t use this function to check whether there is no window in
direction. Calling window-at-side-p described above is a
much more efficient way to do that.
The following function retrieves the entire window tree of a frame:
This function returns a list representing the window tree for frame
frame. If frame is omitted or nil, it defaults to
the selected frame.
The return value is a list of the form (root mini),
where root represents the window tree of the frame’s root
window, and mini is the frame’s minibuffer window.
If the root window is live, root is that window itself.
Otherwise, root is a list (dir edges w1
w2 ...) where dir is nil for a horizontal
combination and t for a vertical combination, edges gives
the size and position of the combination, and the remaining elements
are the child windows. Each child window may again be a window object
(for a live window) or a list with the same format as above (for an
internal window). The edges element is a list (left
top right bottom), similar to the value returned by
window-edges (see Coordinates and Windows).
In each frame, at any time, exactly one Emacs window is designated
as selected within the frame. For the selected frame, that
window is called the selected window—the one in which most
editing takes place, and in which the cursor for selected windows
appears (see Cursor Parameters). Keyboard input that inserts or
deletes text is also normally directed to this window. The selected
window’s buffer is usually also the current buffer, except when
set-buffer has been used (see The Current Buffer). As for
non-selected frames, the window selected within the frame becomes the
selected window if the frame is ever selected.
This function returns the selected window (which is always a live window).
The following function explicitly selects a window and its frame.
This function makes window the selected window and the window
selected within its frame, and selects that frame. It also makes
window’s buffer (see Buffers and Windows) current and sets
that buffer’s value of point to the value of window-point
(see Windows and Point) in window. window must be a live
window. The return value is window.
By default, this function also moves window’s buffer to the front
of the buffer list (see The Buffer List) and makes window the most
recently selected window. If the optional argument norecord is
non-nil, these additional actions are omitted.
In addition, this function by default also tells the display engine to
update the display of window when its frame gets redisplayed the
next time. If norecord is non-nil, such updates are
usually not performed. If, however, norecord equals the special
symbol mark-for-redisplay, the additional actions mentioned above
are omitted but window’s display will be nevertheless updated.
Note that sometimes selecting a window is not enough to show it, or make its frame the top-most frame on display: you may also need to raise the frame or make sure input focus is directed to that frame. See Input Focus.
For historical reasons, Emacs does not run a separate hook whenever a window gets selected. Applications and internal routines often temporarily select a window to perform a few actions on it. They do that either to simplify coding—because many functions by default operate on the selected window when no window argument is specified—or because some functions did not (and still do not) take a window as argument and always operate(d) on the selected window instead. Running a hook every time a window gets selected for a short time and once more when the previously selected window gets restored is not useful.
However, when its norecord argument is nil,
select-window updates the buffer list and thus indirectly runs
the normal hook buffer-list-update-hook (see The Buffer List).
Consequently, that hook provides one way to run a function whenever a
window gets selected more “permanently”.
Since buffer-list-update-hook is also run by functions that are
not related to window management, it will usually make sense to save the
value of the selected window somewhere and compare it with the value of
selected-window while running that hook. Also, to avoid false
positives when using buffer-list-update-hook, it is good practice
that every select-window call supposed to select a window only
temporarily passes a non-nil norecord argument. If
possible, the macro with-selected-window (see below) should be
used in such cases.
Emacs also runs the hook window-selection-change-functions
whenever the redisplay routine detects that another window has been
selected since last redisplay. See Hooks for Window Scrolling and Changes, for a detailed
explanation. window-state-change-functions (described in the
same section) is another abnormal hook run after a different window
has been selected but is triggered by other window changes as well.
The sequence of calls to select-window with a non-nil
norecord argument determines an ordering of windows by their
selection or use time, see below. The function get-lru-window,
for example, can then be used to retrieve the least recently selected
window (see Cyclic Ordering of Windows).
This function returns the window on frame that is selected
within that frame. frame should be a live frame; if omitted or
nil, it defaults to the selected frame.
This function makes window the window selected within the frame
frame. frame should be a live frame; if nil, it
defaults to the selected frame. window must denote a live window.
If frame is the selected frame, this makes window the selected window.
If the optional argument norecord is non-nil, this function
does not alter the ordering of the most recently selected windows, nor
the buffer list.
The following macros are useful to temporarily select a window without affecting the ordering of recently selected windows or the buffer list.
This macro records the selected frame, as well as the selected window of each frame, executes forms in sequence, then restores the earlier selected frame and windows. It also saves and restores the current buffer. It returns the value of the last form in forms.
This macro does not save or restore anything about the sizes, arrangement or contents of windows; therefore, if forms change them, the change persists. If the previously selected window of some frame is no longer live at the time of exit from forms, that frame’s selected window is left alone. If the previously selected window is no longer live, then whatever window is selected at the end of forms remains selected. The current buffer is restored if and only if it is still live when exiting forms.
This macro changes neither the ordering of recently selected windows nor the buffer list.
This macro selects window, executes forms in sequence, then
restores the previously selected window and current buffer. The
ordering of recently selected windows and the buffer list remain
unchanged unless you deliberately change them within forms; for
example, by calling select-window with argument norecord
nil. Hence, this macro is the preferred way to temporarily work
with window as the selected window without needlessly running
buffer-list-update-hook.
Note that this macro temporarily puts the window management code in an
unstable state. In particular, the most recently used window (see below)
will not necessarily match the selected one. Hence, functions like
get-lru-window and get-mru-window may return unexpected
results when called from the body of this macro.
This macro executes forms with frame as the selected frame. The value returned is the value of the last form in forms. This macro saves and restores the selected frame, and changes the order of neither the recently selected windows nor the buffers in the buffer list.
This function returns the use time of window window. window must be a live window and defaults to the selected one.
The use time of a window is not really a time value, but an
integer that does increase monotonically with each call of
select-window with a nil norecord argument. The
window with the lowest use time is usually called the least recently
used window. The window with the highest use time is called the most
recently used one (see Cyclic Ordering of Windows) and is usually the
selected window unless with-selected-window has been used.
This function marks window as being the second most recently
used one (after the selected window). It does nothing if window
is the selected window or the selected window does not have the
highest use time among all windows which may happen within the scope
of with-selected-window.
Sometimes several windows collectively and
cooperatively display a buffer, for example, under the management of
Follow Mode (see (emacs)Follow Mode), where the windows together
display a bigger portion of the buffer than one window could alone.
It is often useful to consider such a window group as a single
entity. Several functions such as window-group-start
(see The Window Start and End Positions) allow you to do this by supplying, as
an argument, one of the windows as a stand-in for the whole group.
When the selected window is a member of a group of windows, this function returns a list of the windows in the group, ordered such that the first window in the list is displaying the earliest part of the buffer, and so on. Otherwise the function returns a list containing just the selected window.
The selected window is considered part of a group when the buffer
local variable selected-window-group-function is set to a
function. In this case, selected-window-group calls it with no
arguments and returns its result (which should be the list of windows
in the group).
Emacs provides miscellaneous functions for finding the height and width
of a window. The return value of many of these functions can be
specified either in units of pixels or in units of lines and columns.
On a graphical display, the latter actually correspond to the height and
width of a default character specified by the frame’s default font as
returned by frame-char-height and frame-char-width
(see Frame Font). Thus, if a window is displaying text with a
different font or size, the reported line height and column width for
that window may differ from the actual number of text lines or columns
displayed within it.
The total height of a window is the number of lines comprising its body and its top and bottom decorations (see Basic Concepts of Emacs Windows).
This function returns the total height, in lines, of the window
window. If window is omitted or nil, it defaults to
the selected window. If window is an internal window, the return
value is the total height occupied by its descendant windows.
If a window’s pixel height is not an integral multiple of its frame’s default character height, the number of lines occupied by the window is rounded internally. This is done in a way such that, if the window is a parent window, the sum of the total heights of all its child windows internally equals the total height of their parent. This means that although two windows have the same pixel height, their internal total heights may differ by one line. This means also, that if window is vertically combined and has a next sibling, the topmost row of that sibling can be calculated as the sum of this window’s topmost row and total height (see Coordinates and Windows)
If the optional argument round is ceiling, this
function returns the smallest integer larger than window’s pixel
height divided by the character height of its frame; if it is
floor, it returns the largest integer smaller than said value;
with any other round it returns the internal value of
windows’s total height.
The total width of a window is the number of columns comprising its body and its left and right decorations (see Basic Concepts of Emacs Windows).
This function returns the total width, in columns, of the window
window. If window is omitted or nil, it defaults to
the selected window. If window is internal, the return value is
the total width occupied by its descendant windows.
If a window’s pixel width is not an integral multiple of its frame’s
character width, the number of columns occupied by the window is rounded
internally. This is done in a way such that, if the window is a parent
window, the sum of the total widths of all its children internally
equals the total width of their parent. This means that although two
windows have the same pixel width, their internal total widths may
differ by one column. This means also, that if this window is
horizontally combined and has a next sibling, the leftmost column of
that sibling can be calculated as the sum of this window’s leftmost
column and total width (see Coordinates and Windows). The optional
argument round behaves as it does for window-total-height.
This function returns either the total height in lines or the total
width in columns of the window window. If horizontal is
omitted or nil, this is equivalent to calling
window-total-height for window; otherwise it is equivalent
to calling window-total-width for window. The optional
argument round behaves as it does for window-total-height.
The following two functions can be used to return the total size of a window in units of pixels.
This function returns the total height of window window in pixels. window must be a valid window and defaults to the selected one.
The return value includes the heights of window’s top and bottom decorations. If window is an internal window, its pixel height is the pixel height of the screen areas spanned by its children.
This function returns the width of window window in pixels. window must be a valid window and defaults to the selected one.
The return value includes the widths of window’s left and right decorations. If window is an internal window, its pixel width is the width of the screen areas spanned by its children.
The following functions can be used to determine whether a given window has any adjacent windows.
This function returns non-nil if window has no other window
above or below it in its frame. More precisely, this means that the
total height of window equals the total height of the root window
on that frame. The minibuffer window does not count in this regard. If
window is omitted or nil, it defaults to the selected
window.
This function returns non-nil if window has no other
window to the left or right in its frame, i.e., its total width equals
that of the root window on that frame. If window is omitted or
nil, it defaults to the selected window.
The body height of a window is the height of its body, which does not include any of its top or bottom decorations (see Basic Concepts of Emacs Windows).
This function returns the height, in lines, of the body of window
window. If window is omitted or nil, it defaults to
the selected window; otherwise it must be a live window.
The optional argument pixelwise defines the units to use for the
height. If nil, return the body height of window in
characters, rounded down to the nearest integer, if necessary. This
means that if a line at the bottom of the text area is only partially
visible, that line is not counted. It also means that the height of a
window’s body can never exceed its total height as returned by
window-total-height.
If pixelwise is remap and the default face is remapped
(see Face Remapping), use the remapped face to determine the
character height. For any other non-nil value, return the
height in pixels.
The body width of a window is the width of its body and of the text area, which does not include any of its left or right decorations (see Basic Concepts of Emacs Windows).
Note that when one or both fringes are removed (by setting their width
to zero), the display engine reserves two character cells, one on each
side of the window, for displaying the continuation and truncation
glyphs, which leaves 2 columns less for text display. (The function
window-max-chars-per-line, described below, takes this
peculiarity into account.)
This function returns the width, in columns, of the body of window
window. If window is omitted or nil, it defaults to
the selected window; otherwise it must be a live window.
The optional argument pixelwise defines the units to use for the
width. If nil, return the body width of window in
characters, rounded down to the nearest integer, if necessary. This
means that if a column on the right of the text area is only partially
visible, that column is not counted. It also means that the width of
a window’s body can never exceed its total width as returned by
window-total-width.
If pixelwise is remap and the default face is remapped
(see Face Remapping), use the remapped face to determine the
character width. For any other non-nil value, return the width
in pixels.
This function returns the body height or body width of window. If
horizontal is omitted or nil, it is equivalent to calling
window-body-height for window; otherwise it is equivalent
to calling window-body-width. In either case, the optional
argument pixelwise is passed to the function called.
The pixel heights of a window’s mode, tab and header line can be retrieved with the functions given below. Their return value is usually accurate unless the window has not been displayed before: In that case, the return value is based on an estimate of the font used for the window’s frame.
This function returns the height in pixels of window’s mode line. window must be a live window and defaults to the selected one. If window has no mode line, the return value is zero.
This function returns the height in pixels of window’s tab line. window must be a live window and defaults to the selected one. If window has no tab line, the return value is zero.
This function returns the height in pixels of window’s header line. window must be a live window and defaults to the selected one. If window has no header line, the return value is zero.
Functions for retrieving the height and/or width of window dividers (see Window Dividers), fringes (see Fringes), scroll bars (see Scroll Bars), and display margins (see Displaying in the Margins) are described in the corresponding sections.
If your Lisp program needs to make layout decisions, you will find the following function useful:
This function returns the number of characters displayed in the
specified face face in the specified window window (which
must be a live window). If face was remapped (see Face Remapping), the information is returned for the remapped face. If
omitted or nil, face defaults to the default face, and
window defaults to the selected window.
Unlike window-body-width, this function accounts for the actual
size of face’s font, instead of working in units of the canonical
character width of window’s frame (see Frame Font). It also
accounts for space used by the continuation glyph, if window lacks
one or both of its fringes.
Commands that change the size of windows (see Resizing Windows),
or split them (see Splitting Windows), obey the variables
window-min-height and window-min-width, which specify the
smallest allowable window height and width. They also obey the variable
window-size-fixed, with which a window can be fixed in
size (see Preserving Window Sizes).
This option specifies the minimum total height, in lines, of any window. Its value has to accommodate at least one text line and any top or bottom decorations.
This option specifies the minimum total width, in columns, of any window. Its value has to accommodate at least two text columns and any left or right decorations.
The following function tells how small a specific window can get taking
into account the sizes of its areas and the values of
window-min-height, window-min-width and
window-size-fixed (see Preserving Window Sizes).
This function returns the minimum size of window. window
must be a valid window and defaults to the selected one. The optional
argument horizontal non-nil means to return the minimum
number of columns of window; otherwise return the minimum number
of window’s lines.
The return value makes sure that all components of window remain
fully visible if window’s size were actually set to it. With
horizontal nil it includes any top or bottom decorations.
With horizontal non-nil it includes any left or right
decorations of window.
The optional argument ignore, if non-nil, means ignore
restrictions imposed by fixed size windows, window-min-height or
window-min-width settings. If ignore equals safe,
live windows may get as small as window-safe-min-height lines and
window-safe-min-width columns. If ignore is a window,
ignore restrictions for that window only. Any other non-nil
value means ignore all of the above restrictions for all windows.
The optional argument pixelwise non-nil means to return the
minimum size of window counted in pixels.
This section describes functions for resizing a window without changing the size of its frame. Because live windows do not overlap, these functions are meaningful only on frames that contain two or more windows: resizing a window also changes the size of at least one other window. If there is just one window on a frame, its size cannot be changed except by resizing the frame (see Frame Size).
Except where noted, these functions also accept internal windows as arguments. Resizing an internal window causes its child windows to be resized to fit the same space.
This function returns delta if the size of window can be
changed vertically by delta lines. If the optional argument
horizontal is non-nil, it instead returns delta if
window can be resized horizontally by delta columns. It
does not actually change the window size.
If window is nil, it defaults to the selected window.
A positive value of delta means to check whether the window can be enlarged by that number of lines or columns; a negative value of delta means to check whether the window can be shrunk by that many lines or columns. If delta is non-zero, a return value of 0 means that the window cannot be resized.
Normally, the variables window-min-height and
window-min-width specify the smallest allowable window size
(see Window Sizes). However, if the optional argument ignore
is non-nil, this function ignores window-min-height and
window-min-width, as well as window-size-fixed. Instead,
it considers the minimum height of a window as the sum of its top and
bottom decorations plus the text of one line; and its minimum width
as the sum of its left and right decorations plus text that takes two
columns.
If the optional argument pixelwise is non-nil,
delta is interpreted as pixels.
This function resizes window by delta increments. If
horizontal is nil, it changes the height by delta
lines; otherwise, it changes the width by delta columns. A
positive delta means to enlarge the window, and a negative
delta means to shrink it.
If window is nil, it defaults to the selected window. If
the window cannot be resized as demanded, an error is signaled.
The optional argument ignore has the same meaning as for the
function window-resizable above.
If the optional argument pixelwise is non-nil,
delta will be interpreted as pixels.
The choice of which window edges this function alters depends on the
values of the option window-combination-resize and the
combination limits of the involved windows; in some cases, it may alter
both edges. See Recombining Windows. To resize by moving only the
bottom or right edge of a window, use the function
adjust-window-trailing-edge.
This function moves window’s bottom edge by delta lines.
If optional argument horizontal is non-nil, it instead
moves the right edge by delta columns. If window is
nil, it defaults to the selected window.
If the optional argument pixelwise is non-nil,
delta is interpreted as pixels.
A positive delta moves the edge downwards or to the right; a negative delta moves it upwards or to the left. If the edge cannot be moved as far as specified by delta, this function moves it as far as possible but does not signal an error.
This function tries to resize windows adjacent to the edge that is moved. If this is not possible for some reason (e.g., if that adjacent window is fixed-size), it may resize other windows.
If the value of this option is non-nil, Emacs resizes windows in
units of pixels. This currently affects functions like
split-window (see Splitting Windows), maximize-window,
minimize-window, fit-window-to-buffer,
fit-frame-to-buffer and
shrink-window-if-larger-than-buffer (all listed below).
Note that when a frame’s pixel size is not a multiple of its character
size, at least one window may get resized pixelwise even if this
option is nil. The default value is nil.
The following commands resize windows in more specific ways. When called interactively, they act on the selected window.
This command adjusts the height or width of window to fit the text
in it. It returns non-nil if it was able to resize window,
and nil otherwise. If window is omitted or nil, it
defaults to the selected window. Otherwise, it should be a live window.
If window is part of a vertical combination, this function adjusts
window’s height. The new height is calculated from the actual
height of the accessible portion of its buffer. The optional argument
max-height, if non-nil, specifies the maximum total height
that this function can give window. The optional argument
min-height, if non-nil, specifies the minimum total height
that it can give, which overrides the variable window-min-height.
Both max-height and min-height are specified in lines and
include any top or bottom decorations of window.
If window is part of a horizontal combination and the value of the
option fit-window-to-buffer-horizontally (see below) is
non-nil, this function adjusts window’s width. The new
width of window is calculated from the maximum length of its
buffer’s lines that follow the current start position of window.
The optional argument max-width specifies a maximum width and
defaults to the width of window’s frame. The optional argument
min-width specifies a minimum width and defaults to
window-min-width. Both max-width and min-width are
specified in columns and include any left or right decorations of
window.
The optional argument preserve-size, if non-nil, will
install a parameter to preserve the size of window during future
resize operations (see Preserving Window Sizes).
If the option fit-frame-to-buffer (see below) is non-nil,
this function will try to resize the frame of window to fit its
contents by calling fit-frame-to-buffer (see below).
If this is non-nil, fit-window-to-buffer can resize
windows horizontally. If this is nil (the default)
fit-window-to-buffer never resizes windows horizontally. If this
is only, it can resize windows horizontally only. Any other
value means fit-window-to-buffer can resize windows in both
dimensions.
If this option is non-nil, fit-window-to-buffer can fit a
frame to its buffer. A frame is fit if and only if its root window is a
live window and this option is non-nil. If this is
horizontally, frames are fit horizontally only. If this is
vertically, frames are fit vertically only. Any other
non-nil value means frames can be resized in both dimensions.
If you have a frame that displays only one window, you can fit that
frame to its buffer using the command fit-frame-to-buffer.
This command adjusts the size of frame to display the contents of its buffer exactly. frame can be any live frame and defaults to the selected one. Fitting is done only if frame’s root window is live.
The arguments max-height, min-height, max-width and
min-width, if non-nil, specify bounds on the new body size
of frame’s root window. A non-nil value specified by any
of these arguments overrides the corresponding value specified by
the option fit-frame-to-buffer-sizes described below.
If the optional argument only is vertically, this function
may resize the frame vertically only. If only is
horizontally, it may resize the frame horizontally only.
The behavior of fit-frame-to-buffer can be controlled with the
help of the two options listed next.
This option can be used to specify margins around frames to be fit by
fit-frame-to-buffer. Such margins can be useful to avoid, for
example, that the resized frame overlaps the taskbar or parts of its
parent frame.
It specifies the numbers of pixels to be left free on the left, above,
the right, and below a frame that shall be fit. The default specifies
nil for each which means to use no margins. The value specified
here can be overridden for a specific frame by that frame’s
fit-frame-to-buffer-margins parameter, if present.
This option specifies size boundaries for fit-frame-to-buffer.
It specifies the maximum and minimum lines and maximum and minimum
columns of the root window’s body of any frame that shall be fit to its
buffer. Any value this option specifies will be overridden by the
corresponding argument of fit-frame-to-buffer, if non-nil.
This command attempts to reduce window’s height as much as
possible while still showing its full buffer, but no less than
window-min-height lines. The return value is non-nil if
the window was resized, and nil otherwise. If window is
omitted or nil, it defaults to the selected window. Otherwise,
it should be a live window.
This command does nothing if the window is already too short to display all of its buffer, or if any of the buffer is scrolled off-screen, or if the window is the only live window in its frame.
This command calls fit-window-to-buffer (see above) to do its
work.
This function balances windows in a way that gives more space to full-width and/or full-height windows. If window-or-frame specifies a frame, it balances all windows on that frame. If window-or-frame specifies a window, it balances only that window and its siblings (see Windows and Frames).
This function attempts to give all windows on the selected frame approximately the same share of the screen area. Full-width or full-height windows are not given more space than other windows.
This function attempts to make window as large as possible, in
both dimensions, without resizing its frame or deleting other windows.
If window is omitted or nil, it defaults to the selected
window.
This function attempts to make window as small as possible, in
both dimensions, without deleting it or resizing its frame. If
window is omitted or nil, it defaults to the selected
window.
A window can get resized explicitly by using one of the functions from the preceding section or implicitly, for example, when resizing an adjacent window, when splitting or deleting a window (see Splitting Windows, see Deleting Windows) or when resizing the window’s frame (see Frame Size).
It is possible to avoid implicit resizing of a specific window when there are one or more other resizable windows on the same frame. For this purpose, Emacs must be advised to preserve the size of that window. There are two basic ways to do that.
If this buffer-local variable is non-nil, the size of any window
displaying the buffer cannot normally be changed. Deleting a window or
changing the frame’s size may still change the window’s size, if there
is no choice.
If the value is height, then only the window’s height is fixed;
if the value is width, then only the window’s width is fixed.
Any other non-nil value fixes both the width and the height.
If this variable is nil, this does not necessarily mean that any
window showing the buffer can be resized in the desired direction. To
determine that, use the function window-resizable.
See Resizing Windows.
Often window-size-fixed is overly aggressive because it inhibits
any attempt to explicitly resize or split an affected window as well.
This may even happen after the window has been resized implicitly, for
example, when deleting an adjacent window or resizing the window’s
frame. The following function tries hard to never disallow resizing
such a window explicitly:
This function (un-)marks the height of window window as preserved
for future resize operations. window must be a live window and
defaults to the selected one. If the optional argument horizontal
is non-nil, it (un-)marks the width of window as preserved.
If the optional argument preserve is t, this means to
preserve the current height/width of window’s body. The
height/width of window will change only if Emacs has no better
choice. Resizing a window whose height/width is preserved by this
function never throws an error.
If preserve is nil, this means to stop preserving the
height/width of window, lifting any respective restraint induced
by a previous call of this function for window. Calling
enlarge-window, shrink-window or
fit-window-to-buffer with window as argument may also
remove the respective restraint.
window-preserve-size is currently invoked by the following
functions:
fit-window-to-bufferIf the optional argument preserve-size of that function
(see Resizing Windows) is non-nil, the size established by
that function is preserved.
display-bufferIf the alist argument of that function (see Choosing a Window for Displaying a Buffer)
contains a preserve-size entry, the size of the window produced
by that function is preserved.
window-preserve-size installs a window parameter (see Window Parameters) called window-preserved-size which is consulted by the
window resizing functions. This parameter will not prevent resizing the
window when the window shows another buffer than the one when
window-preserve-size was invoked or if its size has changed since
then.
The following function can be used to check whether the height of a particular window is preserved:
This function returns the preserved height of window window in
pixels. window must be a live window and defaults to the selected
one. If the optional argument horizontal is non-nil, it
returns the preserved width of window. It returns nil if
the size of window is not preserved.
This section describes functions for creating a new window by splitting an existing one. Note that some windows are special in the sense that these functions may fail to split them as described here. Examples of such windows are side windows (see Side Windows) and atomic windows (see Atomic Windows).
This function creates a new live window next to the window
window. If window is omitted or nil, it defaults
to the selected window. That window is split, and reduced in
size. The space is taken up by the new window, which is returned.
The optional second argument size determines the sizes of
window and/or the new window. If it is omitted or nil,
both windows are given equal sizes; if there is an odd line, it is
allocated to the new window. If size is a positive number,
window is given size lines (or columns, depending on the
value of side). If size is a negative number, the new
window is given −size lines (or columns).
If size is nil, this function obeys the variables
window-min-height and window-min-width (see Window Sizes). Thus, it signals an error if splitting would result in making
a window smaller than those variables specify. However, a
non-nil value for size causes those variables to be
ignored; in that case, the smallest allowable window is considered to be
one that has space for a text that is one line tall and/or two columns
wide.
Hence, if size is specified, it’s the caller’s responsibility to
check whether the emanating windows are large enough to encompass all of
their decorations like a mode line or a scroll bar. The function
window-min-size (see Window Sizes) can be used to determine
the minimum requirements of window in this regard. Since the new
window usually inherits areas like the mode line or the scroll bar from
window, that function is also a good guess for the minimum size of
the new window. The caller should specify a smaller size only if it
correspondingly removes an inherited area before the next redisplay.
The optional third argument side determines the position of the
new window relative to window. If it is nil or
below, the new window is placed below window. If it is
above, the new window is placed above window. In both
these cases, size specifies a total window height, in lines.
If side is t or right, the new window is placed on
the right of window. If side is left, the new
window is placed on the left of window. In both these cases,
size specifies a total window width, in columns.
The optional fourth argument pixelwise, if non-nil, means
to interpret size in units of pixels, instead of lines and
columns.
If window is a live window, the new window inherits various properties from it, including margins and scroll bars. If window is an internal window, the new window inherits the properties of the window selected within window’s frame.
The behavior of this function may be altered by the window parameters
of window, so long as the variable
ignore-window-parameters is nil. If the value of
the split-window window parameter is t, this function
ignores all other window parameters. Otherwise, if the value of the
split-window window parameter is a function, that function is
called with the arguments window, size, and side, in
lieu of the usual action of split-window. Otherwise, this
function obeys the window-atom or window-side window
parameter, if any. See Window Parameters.
As an example, here is a sequence of split-window calls that
yields the window configuration discussed in Windows and Frames.
This example demonstrates splitting a live window as well as splitting
an internal window. We begin with a frame containing a single window
(a live root window), which we denote by W4. Calling
(split-window W4) yields this window configuration:
______________________________________
| ____________________________________ |
|| ||
|| ||
|| ||
||_________________W4_________________||
| ____________________________________ |
|| ||
|| ||
|| ||
||_________________W5_________________||
|__________________W3__________________|
The split-window call has created a new live window, denoted by
W5. It has also created a new internal window, denoted by
W3, which becomes the root window and the parent of both
W4 and W5.
Next, we call (split-window W3 nil 'left), passing the
internal window W3 as the argument. The result:
______________________________________
| ______ ____________________________ |
|| || __________________________ ||
|| ||| |||
|| ||| |||
|| ||| |||
|| |||____________W4____________|||
|| || __________________________ ||
|| ||| |||
|| ||| |||
|| |||____________W5____________|||
||__W2__||_____________W3_____________ |
|__________________W1__________________|
A new live window W2 is created, to the left of the internal window W3. A new internal window W1 is created, becoming the new root window.
For interactive use, Emacs provides two commands which always split
the selected window. These call split-window internally.
This function splits the window window-to-split into two side-by-side windows, putting window-to-split on the left. window-to-split defaults to the selected window. If size is positive, the left window gets size columns; if size is negative, the right window gets −size columns.
This function splits the window window-to-split into two windows, one above the other, leaving the upper window selected. window-to-split defaults to the selected window. If size is positive, the upper window gets size lines; if size is negative, the lower window gets −size lines.
This function splits the whole frame in two. The current window
configuration is retained on the top, and a new window is created
below, taking up the whole width of the frame. size is treated
as by split-window-below.
This function splits the whole frame in two. The current window
configuration is retained on the left, and a new window is created on
the right, taking up the whole height of the frame. size is treated
as by split-window-right.
If the value of this variable is non-nil (the default),
split-window-below behaves as described above.
If it is nil, split-window-below adjusts point in each
of the two windows to minimize redisplay. (This is useful on slow
terminals.) It selects whichever window contains the screen line that
point was previously on. Note that this only affects
split-window-below, not the lower-level split-window
function.
Deleting a window removes it from the frame’s window tree. If the window is a live window, it disappears from the screen. If the window is an internal window, its child windows are deleted too.
Even after a window is deleted, it continues to exist as a Lisp object, until there are no more references to it. Window deletion can be reversed, by restoring a saved window configuration (see Window Configurations).
This function removes window from display and returns
nil. If window is omitted or nil, it defaults to
the selected window.
If deleting the window would leave no more windows in the window tree (e.g., if it is the only live window in the frame) or all remaining windows on window’s frame are side windows (see Side Windows), an error is signaled. If window is part of an atomic window (see Atomic Windows), this function tries to delete the root of that atomic window instead.
By default, the space taken up by window is given to one of its
adjacent sibling windows, if any. However, if the variable
window-combination-resize is non-nil, the space is
proportionally distributed among any remaining windows in the same
window combination. See Recombining Windows.
The behavior of this function may be altered by the window parameters of
window, so long as the variable ignore-window-parameters is
nil. If the value of the delete-window window parameter
is t, this function ignores all other window parameters.
Otherwise, if the value of the delete-window window parameter is
a function, that function is called with the argument window, in
lieu of the usual action of delete-window. See Window Parameters.
When delete-window deletes the selected window of its frame, it
has to make another window the new selected window of that frame. The
following option allows configuring which window is chosen.
This option allows specifying which window should become a frame’s
selected window after delete-window has deleted the previously
selected one. Possible choices are
mru
(the default) choose the most recently used window on that frame.
pos
choose the window comprising the frame coordinates of point of the
previously selected window on that frame.
nil
choose the first window (the window returned by
frame-first-window) on that frame.
A window with a non-nil no-other-window parameter is
chosen only if all other windows on that frame have that parameter set
to a non-nil value too.
This function makes window fill its frame, deleting other
windows as necessary. If window is omitted or nil, it
defaults to the selected window. An error is signaled if window
is a side window (see Side Windows). If window is part of
an atomic window (see Atomic Windows), this function tries to make
the root of that atomic window fill its frame. The return
value is nil.
The behavior of this function may be altered by the window parameters of
window, so long as the variable ignore-window-parameters is
nil. If the value of the delete-other-windows window
parameter is t, this function ignores all other window
parameters. Otherwise, if the value of the delete-other-windows
window parameter is a function, that function is called with the
argument window, in lieu of the usual action of
delete-other-windows. See Window Parameters.
Also, if ignore-window-parameters is nil, this function
does not delete any window whose no-delete-other-windows
parameter is non-nil.
This function deletes all windows showing buffer-or-name, by
calling delete-window on those windows. buffer-or-name
should be a buffer, or the name of a buffer; if omitted or nil,
it defaults to the current buffer. If there are no windows showing
the specified buffer, this function does nothing. If the specified
buffer is a minibuffer, an error is signaled.
If there is a dedicated window showing the buffer, and that window is the only one on its frame, this function also deletes that frame if it is not the only frame on the terminal.
The optional argument frame specifies which frames to operate on:
nil
means operate on all frames.
t
means operate on the selected frame.
visible
means operate on all visible frames.
0
means operate on all visible or iconified frames.
Note that this argument does not have the same meaning as in other
functions which scan all live windows (see Cyclic Ordering of Windows). Specifically, the meanings of t and nil here
are the opposite of what they are in those other functions.
When deleting the last sibling of a window W, its parent window is deleted too, with W replacing it in the window tree. This means that W must be recombined with its parent’s siblings to form a new window combination (see Windows and Frames). In some occasions, deleting a live window may even entail the deletion of two internal windows.
______________________________________
| ______ ____________________________ |
|| || __________________________ ||
|| ||| ___________ ___________ |||
|| |||| || ||||
|| ||||____W6_____||_____W7____||||
|| |||____________W4____________|||
|| || __________________________ ||
|| ||| |||
|| ||| |||
|| |||____________W5____________|||
||__W2__||_____________W3_____________ |
|__________________W1__________________|
Deleting W5 in this configuration normally causes the deletion of W3 and W4. The remaining live windows W2, W6 and W7 are recombined to form a new horizontal combination with parent W1.
Sometimes, however, it makes sense to not delete a parent window like W4. In particular, a parent window should not be removed when it was used to preserve a combination embedded in a combination of the same type. Such embeddings make sense to assure that when you split a window and subsequently delete the new window, Emacs reestablishes the layout of the associated frame as it existed before the splitting.
Consider a scenario starting with two live windows W2 and W3 and their parent W1.
______________________________________
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W3_________________||
|__________________W1__________________|
Split W2 to make a new window W4 as follows.
______________________________________
| ____________________________________ |
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W4_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W3_________________||
|__________________W1__________________|
Now, when enlarging a window vertically, Emacs tries to obtain the corresponding space from its lower sibling, provided such a window exists. In our scenario, enlarging W4 will steal space from W3.
______________________________________
| ____________________________________ |
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
||_________________W4_________________||
| ____________________________________ |
||_________________W3_________________||
|__________________W1__________________|
Deleting W4 will now give its entire space to W2, including the space earlier stolen from W3.
______________________________________
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
|| ||
|| ||
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
||_________________W3_________________||
|__________________W1__________________|
This can be counterintuitive, in particular if W4 were used for displaying a buffer only temporarily (see Temporary Displays), and you want to continue working with the initial layout.
The behavior can be fixed by making a new parent window when splitting W2. The variable described next allows that to be done.
This variable controls whether splitting a window shall make a new parent window. The following values are recognized:
nilThis means that the new live window is allowed to share the existing parent window, if one exists, provided the split occurs in the same direction as the existing window combination (otherwise, a new internal window is created anyway).
window-sizeThis means that display-buffer makes a new parent window when
it splits a window and is passed a window-height or
window-width entry in the alist argument (see Action Functions for Buffer Display). Otherwise, window splitting behaves as
for a value of nil.
temp-buffer-resizeIn this case with-temp-buffer-window makes a new parent window
when it splits a window and temp-buffer-resize-mode is enabled
(see Temporary Displays). Otherwise, window splitting behaves as
for nil.
temp-bufferIn this case with-temp-buffer-window always makes a new parent
window when it splits an existing window (see Temporary Displays).
Otherwise, window splitting behaves as for nil.
display-bufferThis means that when display-buffer (see Choosing a Window for Displaying a Buffer)
splits a window it always makes a new parent window. Otherwise, window
splitting behaves as for nil.
tThis means that splitting a window always creates a new parent window.
Thus, if the value of this variable is at all times t, then at
all times every window tree is a binary tree (a tree where each window
except the root window has exactly one sibling).
The default is window-size. Other values are reserved for future
use.
If, as a consequence of this variable’s setting, split-window
makes a new parent window, it also calls
set-window-combination-limit (see below) on the newly-created
internal window. This affects how the window tree is rearranged when
the child windows are deleted (see below).
If window-combination-limit is t, splitting W2 in
the initial configuration of our scenario would have produced this:
______________________________________
| ____________________________________ |
|| __________________________________ ||
||| |||
|||________________W2________________|||
|| __________________________________ ||
||| |||
|||________________W4________________|||
||_________________W5_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W3_________________||
|__________________W1__________________|
A new internal window W5 has been created; its children are W2 and the new live window W4. Now, W2 is the only sibling of W4, so enlarging W4 will try to shrink W2, leaving W3 unaffected. Observe that W5 represents a vertical combination of two windows embedded in the vertical combination W1.
This function sets the combination limit of the window
window to limit. This value can be retrieved via the
function window-combination-limit. See below for its effects;
note that it is only meaningful for internal windows. The
split-window function automatically calls this function, passing
it t as limit, provided the value of the variable
window-combination-limit is t when it is called.
This function returns the combination limit for window.
The combination limit is meaningful only for an internal window. If it
is nil, then Emacs is allowed to automatically delete
window, in response to a window deletion, in order to group the
child windows of window with its sibling windows to form a new
window combination. If the combination limit is t, the child
windows of window are never automatically recombined with its
siblings.
If, in the configuration shown at the beginning of this section, the
combination limit of W4 (the parent window of W6 and
W7) is t, deleting W5 will not implicitly delete
W4 too.
Alternatively, the problems sketched above can be avoided by always resizing all windows in the same combination whenever one of its windows is split or deleted. This also permits splitting windows that would be otherwise too small for such an operation.
If this variable is nil, split-window can only split a
window (denoted by window) if window’s screen area is large
enough to accommodate both itself and the new window.
If this variable is t, split-window tries to resize all
windows that are part of the same combination as window, in order
to accommodate the new window. In particular, this may allow
split-window to succeed even if window is a fixed-size
window or too small to ordinarily split. Furthermore, subsequently
resizing or deleting window may resize all other windows in its
combination.
The default is nil. Other values are reserved for future use. A
specific split operation may ignore the value of this variable if it is
affected by a non-nil value of window-combination-limit.
To illustrate the effect of window-combination-resize, consider
the following frame layout.
______________________________________
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
||_________________W3_________________||
|__________________W1__________________|
If window-combination-resize is nil, splitting window
W3 leaves the size of W2 unchanged:
______________________________________
| ____________________________________ |
|| ||
|| ||
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
||_________________W3_________________||
| ____________________________________ |
|| ||
||_________________W4_________________||
|__________________W1__________________|
If window-combination-resize is t, splitting W3
instead leaves all three live windows with approximately the same
height:
______________________________________
| ____________________________________ |
|| ||
|| ||
||_________________W2_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W3_________________||
| ____________________________________ |
|| ||
|| ||
||_________________W4_________________||
|__________________W1__________________|
Deleting any of the live windows W2, W3 or W4 will distribute its space proportionally among the two remaining live windows.
When you use the command C-x o (other-window) to select
some other window, it moves through live windows in a specific order.
For any given configuration of windows, this order never varies. It
is called the cyclic ordering of windows.
The ordering is determined by a depth-first traversal of each frame’s window tree, retrieving the live windows which are the leaf nodes of the tree (see Windows and Frames). If the minibuffer is active, the minibuffer window is included too. The ordering is cyclic, so the last window in the sequence is followed by the first one.
This function returns a live window, the one following window in
the cyclic ordering of windows. window should be a live window;
if omitted or nil, it defaults to the selected window.
The optional argument minibuf specifies whether minibuffer windows
should be included in the cyclic ordering. Normally, when minibuf
is nil, a minibuffer window is included only if it is currently
active; this matches the behavior of C-x o. (Note that a
minibuffer window is active as long as its minibuffer is in use; see
迷你缓冲区).
If minibuf is t, the cyclic ordering includes all
minibuffer windows. If minibuf is neither t nor
nil, minibuffer windows are not included even if they are active.
The optional argument all-frames specifies which frames to consider:
nil
means to consider windows on window’s frame. If the minibuffer
window is considered (as specified by the minibuf argument),
then frames that share the minibuffer window are considered too.
t
means to consider windows on all existing frames.
visible
means to consider windows on all visible frames.
If more than one frame is considered, the cyclic ordering is obtained by appending the orderings for those frames, in the same order as the list of all live frames (see Finding All Frames).
This function returns a live window, the one preceding window in
the cyclic ordering of windows. The other arguments are handled like
in next-window.
This function selects a live window, one count places from the selected window in the cyclic ordering of windows. If count is a positive number, it skips count windows forwards; if count is negative, it skips −count windows backwards; if count is zero, that simply re-selects the selected window. When called interactively, count is the numeric prefix argument.
The optional argument all-frames has the same meaning as in
next-window, like a nil minibuf argument to
next-window. When called interactively, all-frames is
always nil, so only windows on the selected frame can be
selected.
This function does not select a window that has a non-nil
no-other-window window parameter (see Window Parameters),
provided that ignore-window-parameters is nil.
If the other-window parameter of the selected window is a
function, and ignore-window-parameters is nil, that
function will be called with the arguments count and
all-frames instead of the normal operation of this function.
This function calls the function fun once for each live window, with the window as the argument.
It follows the cyclic ordering of windows. The optional arguments
minibuf and all-frames specify the set of windows
included; these have the same arguments as in next-window. If
all-frames specifies a frame, the first window walked is the
first window on that frame (the one returned by
frame-first-window), not necessarily the selected window.
If fun changes the window configuration by splitting or deleting windows, that does not alter the set of windows walked, which is determined prior to calling fun for the first time.
This function returns t if the selected window is the only live
window, and nil otherwise.
If the minibuffer window is active, it is normally considered (so that
this function returns nil). However, if the optional argument
no-mini is non-nil, the minibuffer window is ignored even
if active. The optional argument all-frames has the same
meaning as for next-window.
The following functions return a window which satisfies some criterion, without selecting it:
This function returns a live window which is heuristically the least
recently used one. The least recently used window is the least
recently selected one—the window whose use time is less than the use
time of all other live windows (see Selecting Windows). The
optional argument all-frames has the same meaning as in
next-window.
If any full-width windows are present, only those windows are
considered. A minibuffer window is never a candidate. A dedicated
window (see Dedicated Windows) is never a candidate unless the
optional argument dedicated is non-nil. The selected
window is never returned, unless it is the only candidate. However, if
the optional argument not-selected is non-nil, this
function returns nil in that case. The optional argument
no-other, if non-nil, means to never return a window whose
no-other-window parameter is non-nil.
This function is like get-lru-window, but it returns the most
recently used window instead. The most recently used window is
the most recently selected one—the window whose use time exceeds the
use time of all other live windows (see Selecting Windows). The
meaning of the arguments is the same as for get-lru-window.
Since in practice the most recently used window is always the selected
one, it usually makes sense to call this function with a non-nil
not-selected argument only.
This function returns the window with the largest area (height times
width). If there are two candidate windows of the same size, it prefers
the one that comes first in the cyclic ordering of windows, starting
from the selected window. The meaning of the arguments is the same as
for get-lru-window.
This function calls the function predicate for each of the
windows in the cyclic order of windows in turn, passing it the window
as an argument. If the predicate returns non-nil for any
window, this function stops and returns that window. If no such
window is found, the return value is default (which defaults to
nil).
The optional arguments minibuf and all-frames specify the
windows to search, and have the same meanings as in
next-window.
This section describes low-level functions for examining and setting the contents of windows. See Switching to a Buffer in a Window, for higher-level functions for displaying a specific buffer in a window.
This function returns the buffer that window is displaying. If
window is omitted or nil it defaults to the selected
window. If window is an internal window, this function returns
nil.
This function makes window display buffer-or-name.
window should be a live window; if nil, it defaults to
the selected window. buffer-or-name should be a buffer, or the
name of an existing buffer. This function does not change which
window is selected, nor does it directly change which buffer is
current (see The Current Buffer). Its return value is nil.
If window is strongly dedicated to a buffer and buffer-or-name does not specify that buffer, this function signals an error. See Dedicated Windows.
By default, this function resets window’s position, display
margins, fringe widths, and scroll bar settings, based on the local
variables in the specified buffer. However, if the optional argument
keep-margins is non-nil, it leaves window’s display
margins, fringes and scroll bar settings alone.
When writing an application, you should normally use
display-buffer (see Choosing a Window for Displaying a Buffer) or the higher-level
functions described in Switching to a Buffer in a Window, instead of calling
set-window-buffer directly.
This runs window-scroll-functions, followed by
window-configuration-change-hook. See Hooks for Window Scrolling and Changes.
This buffer-local variable records the number of times a buffer has been
displayed in a window. It is incremented each time
set-window-buffer is called for the buffer.
This buffer-local variable records the time at which a buffer was last
displayed in a window. The value is nil if the buffer has
never been displayed. It is updated each time
set-window-buffer is called for the buffer, with the value
returned by current-time (see Time of Day).
This function returns the first window displaying buffer-or-name
in the cyclic ordering of windows, starting from the selected window
(see Cyclic Ordering of Windows). If no such window exists, the
return value is nil.
buffer-or-name should be a buffer or the name of a buffer; if
omitted or nil, it defaults to the current buffer. The
optional argument all-frames specifies which windows to
consider:
t means consider windows on all existing frames.
visible means consider windows on all visible frames.
Note that these meanings differ slightly from those of the
all-frames argument to next-window (see Cyclic Ordering of Windows). This function may be changed in a future version of Emacs
to eliminate this discrepancy.
This function returns a list of all windows currently displaying
buffer-or-name. buffer-or-name should be a buffer or the
name of an existing buffer. If omitted or nil, it defaults to
the current buffer. If the currently selected window displays
buffer-or-name, it will be the first in the list returned by
this function.
The arguments minibuf and all-frames have the same
meanings as in the function next-window (see Cyclic Ordering of Windows). Note that the all-frames argument does not
behave exactly like in get-buffer-window.
This command replaces buffer-or-name with some other buffer, in
all windows displaying it. buffer-or-name should be a buffer, or
the name of an existing buffer; if omitted or nil, it defaults to
the current buffer.
The replacement buffer in each window is chosen via
switch-to-prev-buffer (see Window History). With the
exception of side windows (see Side Windows), any dedicated window
displaying buffer-or-name is deleted if possible (see Dedicated Windows). If such a window is the only window on its frame and there
are other frames on the same terminal, the frame is deleted as well.
If the dedicated window is the only window on the only frame on its
terminal, the buffer is replaced anyway.
This section describes high-level functions for switching to a specified buffer in some window. In general, “switching to a buffer” means to (1) show the buffer in some window, (2) make that window the selected window (and its frame the selected frame), and (3) make the buffer the current buffer.
Do not use these functions to make a buffer temporarily
current just so a Lisp program can access or modify it. They have
side-effects, such as changing window histories (see Window History), which will surprise the user if used that way. If you want
to make a buffer current to modify it in Lisp, use
with-current-buffer, save-current-buffer, or
set-buffer. See The Current Buffer.
This command attempts to display buffer-or-name in the selected window and make it the current buffer. It is often used interactively (as the binding of C-x b), as well as in Lisp programs. The return value is the buffer switched to.
If buffer-or-name is nil, it defaults to the buffer
returned by other-buffer (see The Buffer List). If
buffer-or-name is a string that is not the name of any existing
buffer, this function creates a new buffer with that name; the new
buffer’s major mode is determined by the variable major-mode
(see 主模式).
Normally, the specified buffer is put at the front of the buffer
list—both the global buffer list and the selected frame’s buffer
list (see The Buffer List). However, this is not done if the
optional argument norecord is non-nil.
Sometimes, the selected window may not be suitable for displaying the
buffer. This happens if the selected window is a minibuffer window, or
if the selected window is strongly dedicated to its buffer
(see Dedicated Windows). In such cases, the command normally tries
to display the buffer in some other window, by invoking
pop-to-buffer (see below).
If the optional argument force-same-window is non-nil and
the selected window is not suitable for displaying the buffer, this
function always signals an error when called non-interactively. In
interactive use, if the selected window is a minibuffer window, this
function will try to use some other window instead. If the selected
window is strongly dedicated to its buffer, the option
switch-to-buffer-in-dedicated-window described next can be used
to proceed.
This option, if non-nil, allows switch-to-buffer to
proceed when called interactively and the selected window is strongly
dedicated to its buffer.
The following values are respected:
nilDisallows switching and signals an error as in non-interactive use.
promptPrompts the user whether to allow switching.
popInvokes pop-to-buffer to proceed.
tMarks the selected window as non-dedicated and proceeds.
This option does not affect non-interactive calls of
switch-to-buffer.
By default, switch-to-buffer tries to preserve
window-point. This behavior can be tuned using the following
option.
If this variable is nil, switch-to-buffer displays the
buffer specified by buffer-or-name at the position of that
buffer’s point. If this variable is already-displayed, it
tries to display the buffer at its previous position in the selected
window, provided the buffer is currently displayed in some other window
on any visible or iconified frame. If this variable is t,
switch-to-buffer unconditionally tries to display the buffer at
its previous position in the selected window.
This variable is ignored if the buffer is already displayed in the
selected window or never appeared in it before, or if
switch-to-buffer calls pop-to-buffer to display the
buffer.
If this variable is non-nil, switch-to-buffer respects
display actions specified by display-buffer-overriding-action,
display-buffer-alist and other display related variables.
The next two commands are similar to switch-to-buffer, except for
the described features.
This function displays the buffer specified by buffer-or-name in
some window other than the selected window. It uses the function
pop-to-buffer internally (see below).
If the selected window already displays the specified buffer, it continues to do so, but another window is nonetheless found to display it as well.
The buffer-or-name and norecord arguments have the same
meanings as in switch-to-buffer.
This function displays the buffer specified by buffer-or-name in a
new frame. It uses the function pop-to-buffer internally (see
below).
If the specified buffer is already displayed in another window, in any frame on the current terminal, this switches to that window instead of creating a new frame. However, the selected window is never used for this.
The buffer-or-name and norecord arguments have the same
meanings as in switch-to-buffer.
The above commands use the function pop-to-buffer, which
flexibly displays a buffer in some window and selects that window for
editing. In turn, pop-to-buffer uses display-buffer for
displaying the buffer. Hence, all the variables affecting
display-buffer will affect it as well. See Choosing a Window for Displaying a Buffer,
for the documentation of display-buffer.
This function makes buffer-or-name the current buffer and displays it in some window, preferably not the window currently selected. It then selects the displaying window. If that window is on a different graphical frame, that frame is given input focus if possible (see Input Focus).
If buffer-or-name is nil, it defaults to the buffer
returned by other-buffer (see The Buffer List). If
buffer-or-name is a string that is not the name of any existing
buffer, this function creates a new buffer with that name; the new
buffer’s major mode is determined by the variable major-mode
(see 主模式). In any case, that buffer is made current and
returned, even when no suitable window was found to display it.
If action is non-nil, it should be a display action to
pass to display-buffer (see Choosing a Window for Displaying a Buffer).
Alternatively, a non-nil, non-list value means to pop to a
window other than the selected one—even if the buffer is already
displayed in the selected window.
Like switch-to-buffer, this function updates the buffer list
unless norecord is non-nil.
This section describes lower-level functions Emacs uses to find or
create a window for displaying a specified buffer. The common
workhorse of these functions is display-buffer which eventually
handles all incoming requests for buffer display (see Choosing a Window for Displaying a Buffer).
display-buffer delegates the task of finding a suitable
window to so-called action functions (see Action Functions for Buffer Display). First, display-buffer compiles a so-called action
alist—a special association list that action functions can use to
fine-tune their behavior. Then it passes that alist on to each action
function it calls (see Action Alists for Buffer Display).
The behavior of display-buffer is highly customizable. To
understand how customizations are used in practice, you may wish to
study examples illustrating the order of precedence which
display-buffer uses to call action functions (see Precedence of Action Functions). To avoid conflicts between Lisp programs
calling display-buffer and user customizations of its behavior,
it may make sense to follow a number of guidelines which are sketched
in the final part of this section (see The Zen of Buffer Display).
The command display-buffer flexibly chooses a window for
display, and displays a specified buffer in that window. It can be
called interactively, via the key binding C-x 4 C-o. It is also
used as a subroutine by many functions and commands, including
switch-to-buffer and pop-to-buffer (see Switching to a Buffer in a Window).
This command performs several complex steps to find a window to
display in. These steps are described by means of display
actions, which have the form (functions . alist).
Here, functions is either a single function or a list of
functions, referred to as “action functions” (see Action Functions for Buffer Display); and alist is an association list, referred
to as “action alist” (see Action Alists for Buffer Display).
See The Zen of Buffer Display, for samples of display actions.
An action function accepts two arguments: the buffer to display and
an action alist. It attempts to display the buffer in some window,
picking or creating a window according to its own criteria. If
successful, it returns the window; otherwise, it returns nil.
display-buffer works by combining display actions from
several sources, and calling the action functions in turn, until one
of them manages to display the buffer and returns a non-nil
value.
This command makes buffer-or-name appear in some window, without
selecting the window or making the buffer current. The argument
buffer-or-name must be a buffer or the name of an existing
buffer. The return value is the window chosen to display the buffer,
or nil if no suitable window was found.
The optional argument action, if non-nil, should normally
be a display action (described above). display-buffer builds a
list of action functions and an action alist, by consolidating display
actions from the following sources (in order of their precedence,
from highest to lowest):
display-buffer-overriding-action.
display-buffer-alist.
display-buffer-base-action.
display-buffer-fallback-action.
In practice this means that display-buffer builds a list of all
action functions specified by these display actions. The first
element of this list is the first action function specified by
display-buffer-overriding-action, if any. Its last element is
display-buffer-pop-up-frame—the last action function
specified by display-buffer-fallback-action. Duplicates are
not removed from this list—hence one and the same action function
may be called multiple times during one call of display-buffer.
display-buffer calls the action functions specified by this
list in turn, passing the buffer as the first argument and the
combined action alist as the second argument, until one of the
functions returns non-nil. See Precedence of Action Functions, for examples how display actions specified by different
sources are processed by display-buffer.
Note that the second argument is always the list of all action
alist entries specified by the sources named above. Hence, the first
element of that list is the first action alist entry specified by
display-buffer-overriding-action, if any. Its last element is
the last alist entry of display-buffer-base-action, if any (the
action alist of display-buffer-fallback-action is empty).
Note also, that the combined action alist may contain duplicate entries and entries for the same key with different values. As a rule, action functions always use the first association of a key they find. Hence, the association an action function uses is not necessarily the association provided by the display action that specified that action function,
The argument action can also have a non-nil, non-list
value. This has the special meaning that the buffer should be
displayed in a window other than the selected one, even if the
selected window is already displaying it. If called interactively
with a prefix argument, action is t. Lisp programs
should always supply a list value.
The optional argument frame, if non-nil, specifies which
frames to check when deciding whether the buffer is already displayed.
It is equivalent to adding an element (reusable-frames . frame) to the action alist of action (see Action Alists for Buffer Display). The frame argument is provided for
compatibility reasons, Lisp programs should not use it.
The value of this variable should be a display action, which is
treated with the highest priority by display-buffer. The
default value is an empty display action, i.e., (nil . nil).
The value of this option is an alist mapping conditions to display
actions. Each condition is passed to buffer-match-p
(see The Buffer List), along with the buffer name and the action
argument passed to display-buffer. If it returns a
non-nil value, then display-buffer uses the
corresponding display action to display the buffer. Caveat: if you
use derived-mode or major-mode as condition,
buffer-match-p could fail to report a match if
display-buffer is called before the major mode of the buffer is
set.
If the caller of display-buffer passes a category as a symbol
in its action argument, then you can use the same category in
display-buffer-alist to match buffers with different names,
for example:
(add-to-list 'display-buffer-alist
'((category . comint)
(display-buffer-same-window)
(inhibit-same-window . nil)))
(display-buffer (get-buffer-create "*my-shell*")
'(nil (category . comint)))
See buffer-match-p.
Regardless of the displayed buffer’s name the caller defines a category
as a symbol comint. Then display-buffer-alist matches
this category for all buffers displayed with the same category.
This avoids the need to construct a complex regular expression
that matches a buffer name.
The value of this option should be a display action. This option can
be used to define a standard display action for calls to
display-buffer.
This display action specifies the fallback behavior for
display-buffer if no other display actions are given.
An action function is a function display-buffer calls for
choosing a window to display a buffer. Action functions take two
arguments: buffer, the buffer to display, and alist, an
action alist (see Action Alists for Buffer Display). They are
supposed to return a window displaying buffer if they succeed
and nil if they fail.
The following basic action functions are defined in Emacs.
This function tries to display buffer in the selected window.
It fails if the selected window is a minibuffer window or is dedicated
to another buffer (see Dedicated Windows). It also fails if
alist has a non-nil inhibit-same-window entry.
This function tries to display buffer by finding a window that is already displaying it. Windows on the selected frame are preferred to windows on other frames.
If alist has a non-nil inhibit-same-window entry,
the selected window is not eligible for reuse. The set of frames to
search for a window already displaying buffer can be specified
with the help of the reusable-frames action alist entry. If
alist contains no reusable-frames entry, this function
searches just the selected frame.
If this function chooses a window on another frame, it makes that
frame visible and, unless alist contains an
inhibit-switch-frame entry, raises that frame if necessary.
This function tries to display buffer by finding a window that is displaying a buffer in a given mode.
If alist contains a mode entry, its value specifies a
major mode (a symbol) or a list of major modes. If alist
contains no mode entry, the current major mode of buffer
is used instead. A window is a candidate if it displays a buffer
whose mode derives from one of the modes specified thusly.
The behavior is also controlled by alist entries for
inhibit-same-window, reusable-frames and
inhibit-switch-frame, like display-buffer-reuse-window
does.
This function tries to display buffer by splitting the largest
or least recently-used window (usually located on the selected frame).
It actually performs the split by calling the function specified by
split-window-preferred-function (see Additional Options for Displaying Buffers).
The size of the new window can be adjusted by supplying
window-height and window-width entries in alist.
If alist contains a preserve-size entry, Emacs will also
try to preserve the size of the new window during future resize
operations (see Preserving Window Sizes).
This function fails if no window can be split. More often than not,
this happens because no window is large enough to allow splitting.
Setting split-height-threshold or split-width-threshold
to lower values may help in this regard. Splitting also fails when
the selected frame has an unsplittable frame parameter;
see Buffer Parameters.
This function tries to display buffer in a window where it was displayed previously.
If alist contains a non-nil inhibit-same-window
entry, the selected window is not eligible for use. A dedicated
window is usable only if it already shows buffer. If
alist contains a previous-window entry, the window
specified by that entry is usable even if it never showed buffer
before.
If alist contains a reusable-frames entry (see Action Alists for Buffer Display), its value determines which frames to search
for a suitable window. If alist contains no
reusable-frames entry, this function searches just the selected
frame if display-buffer-reuse-frames and pop-up-frames
are both nil; it searches all frames on the current terminal if
either of those variables is non-nil.
If more than one window qualifies as usable according to these rules, this function makes a choice in the following order of preference:
previous-window alist entry,
provided it is not the selected window.
previous-window alist entry or showed buffer
before.
This function tries to display buffer by choosing an existing
window and displaying the buffer in that window. It first tries to find
a window that has not been used recently (see Cyclic Ordering of Windows) on any frame specified by a lru-frames alist
entry, falling back to the selected frame if no such entry exists. It
also prefers windows that satisfy the constraints specified by
window-min-width and window-min-height alist
entries; preferring full-width windows if no window-min-width
entry is found. Finally, it will not return a window whose use time is
higher than that specified by any lru-time entry provided by
alist.
If no less recently used window is found, this function will try to use some other window, preferably a large window on some visible frame. It can fail if all windows are dedicated to other buffers (see Dedicated Windows).
The above describes the behavior when the some-window alist
entry is lru or nil which is the default. Another
possible value is mru. If, for example,
display-buffer-base-action is customized to (nil . ((some-window . mru))), then this function will prefer the most
recently used window. This will try to display several buffers from
consecutive calls of display-buffer in the same window. Consider
a configuration of three or more windows where a user wants to consult,
in a non-selected window, one after the other, the results of a query
spread among several buffers. With the lru strategy, Emacs may
continuously choose another window because the least recently used
window changes with every call of display-buffer-use-some-window.
With the mru strategy, the window chosen would always remain the
same, resulting in a predictable user experience.
This function is similar to display-buffer-use-some-window, but
will try harder to not use a recently used window. In particular,
it does not use the selected window. In addition, it will first try to
reuse a window that shows buffer already, base the decision
whether it should use a window showing another buffer on that window’s
use time alone and pop up a new window if no usable window is found.
Finally, this function will bump the use time (see Selecting Windows) of any window it returns in order to avoid that further
invocations will use that window for showing another buffer. An
application that wants to display several buffers in a row can help this
function by providing a lru-time alist entry it has
initially set to the value of the selected window’s use time. Each
invocation of this function will then bump the use time of the window
returned to a value higher than that and a subsequent invocation will
inhibit this function to use a window it returned earlier.
This function tries to display buffer at a location specified by
alist. For this purpose, alist should contain a
direction entry whose value is one of left, above
(or up), right and below (or down). Other
values are usually interpreted as below.
If alist also contains a window entry, its value
specifies a reference window. That value can be a special symbol like
main which stands for the selected frame’s main window
(see Side Window Options and Functions) or root standing
for the selected frame’s root window (see Windows and Frames). It
can also specify an arbitrary valid window. Any other value (or
omitting the window entry entirely) means to use the selected
window as reference window.
This function first tries to reuse a window in the specified direction
that already shows buffer. If no such window exists, it tries
to split the reference window in order to produce a new window in the
specified direction. If this fails as well, it will try to display
buffer in an existing window in the specified direction. In
either case, the window chosen will appear on the side of the
reference window specified by the direction entry, sharing at
least one edge with the reference window.
If the reference window is live, the edge the chosen window will share
with it is always the opposite of the one specified by the
direction entry. For example, if the value of the
direction entry is left, the chosen window’s right edge
coordinate (see Coordinates and Windows) will equal the reference
window’s left edge coordinate.
If the reference window is internal, a reused window must share with
it the edge specified by the direction entry. Hence if, for
example, the reference window is the frame’s root window and the value
of the direction entry is left, a reused window must be
on the left of the frame. This means that the left edge coordinate of
the chosen window and that of the reference window are the same.
A new window, however, will be created by splitting the reference window such that the chosen window will share the opposite edge with the reference window. In our example, a new root window would be created with a new live window and the reference window as its children. The chosen window’s right edge coordinate would then equal the left edge coordinate of the reference window. Its left edge coordinate would equal the left edge coordinate of the frame’s new root window.
Four special values for direction entries allow implicitly
specifying the selected frame’s main window as the reference window:
leftmost, top, rightmost and bottom. This
means that instead of, for example, (direction . left) (window . main) one can just specify (direction . leftmost). An existing window alist entry is ignored
in such cases.
This function tries to display buffer in a window below the selected window. If there is a window below the selected one and that window already displays buffer, it reuses that window.
If there is no such window, this function tries to create a new window
by splitting the selected one, and displays buffer there. It will
also try to adjust that window’s size provided alist contains a
suitable window-height or window-width entry, see above.
If splitting the selected window fails and there is a non-dedicated window below the selected one showing some other buffer, this function tries to use that window for showing buffer.
If alist contains a window-min-height entry, this
function ensures that the window used is or can become at least as
high as specified by that entry’s value. Note that this is only a
guarantee. In order to actually resize the window used, alist
must also provide an appropriate window-height entry.
This function tries to display buffer in a window at the bottom of the selected frame.
This either tries to split the window at the bottom of the frame or the frame’s root window, or to reuse an existing window at the bottom of the selected frame.
This function creates a new frame, and displays the buffer in that
frame’s window. It actually performs the frame creation by calling
the function specified in pop-up-frame-function
(see Additional Options for Displaying Buffers). If alist contains a
pop-up-frame-parameters entry, the associated value is added to
the newly created frame’s parameters.
This function displays the buffer on the current frame, deleting all other windows so that it takes up the full frame.
This function tries to display buffer in a child frame
(see Child Frames) of the selected frame, either reusing an
existing child frame or by making a new one. If alist has a
non-nil child-frame-parameters entry, the corresponding
value is an alist of frame parameters to give the new frame. A
parent-frame parameter specifying the selected frame is
provided by default. If the child frame should become the child of
another frame, a corresponding entry must be added to alist.
The appearance of child frames is largely dependent on the parameters
provided via alist. It is advisable to use at least ratios to
specify the size (see Size Parameters) and the position
(see Position Parameters) of the child frame, and to add a
keep-ratio parameter (see Frame Interaction Parameters), in
order to make sure that the child frame remains visible. For other
parameters that should be considered see Child Frames.
This function tries to display buffer by finding a frame that meets a predicate (by default any frame other than the selected frame).
If this function chooses a window on another frame, it makes that
frame visible and, unless alist contains an
inhibit-switch-frame entry, raises that frame if necessary.
If alist has a non-nil frame-predicate entry, its
value is a function taking one argument (a frame), returning
non-nil if the frame is a candidate; this function replaces the
default predicate.
If alist has a non-nil inhibit-same-window entry,
the selected window is not used; thus if the selected frame has a
single window, it is not used.
If alist has a non-nil allow-no-window entry, then
this function does not display buffer and returns the symbol
fail. This constitutes the only exception to the convention
that an action function returns either nil or a window showing
buffer. If alist has no such allow-no-window
entry, this function returns nil.
If this function returns fail, display-buffer will skip
the execution of any further display actions and return nil
immediately. If this function returns nil,
display-buffer will continue with the next display action, if
any.
It is assumed that when a caller of display-buffer specifies a
non-nil allow-no-window entry, it is also able to handle
a nil return value.
Two other action functions are described in their proper
sections—display-buffer-in-side-window (see Displaying Buffers in Side Windows) and display-buffer-in-atom-window
(see Atomic Windows).
An action alist is an association list mapping predefined
symbols recognized by action functions to values these functions are
supposed to interpret accordingly. In each call,
display-buffer constructs a new, possibly empty action alist
and passes that entire list on to any action function it calls.
By design, action functions are free in their interpretation of
action alist entries. In fact, some entries like
allow-no-window or previous-window have a meaning only
for one or a few action functions, and are ignored by the rest. Other
entries, like inhibit-same-window or window-parameters,
are supposed to be respected by most action functions, including those
provided by application programs and external packages.
In the previous subsection we have described in detail how
individual action functions interpret the action alist entries they
care about. Here we give a reference list of all known action alist
entries according to their symbols, together with their values and
action functions (see Action Functions for Buffer Display) that
recognize them. Throughout this list, the terms “buffer” will refer
to the buffer display-buffer is supposed to display, and
“value” refers to the entry’s value.
inhibit-same-window ¶If the value is non-nil, this signals that the selected window
must not be used for displaying the buffer. All action functions that
(re-)use an existing window should respect this entry.
previous-window ¶The value must specify a window that may have displayed the buffer
previously. display-buffer-in-previous-window will give
preference to such a window provided it is still live and not
dedicated to another buffer.
mode ¶The value is either a major mode or a list of major modes.
display-buffer-reuse-mode-window may reuse a window whenever
the value specified by this entry matches the major mode of that
window’s buffer. Other action functions ignore such entries.
frame-predicate ¶The value must be a function taking one argument (a frame), supposed
to return non-nil if that frame is a candidate for displaying
the buffer. This entry is used by
display-buffer-use-some-frame.
reusable-frames ¶The value specifies the set of frames to search for a window that can be reused because it already displays the buffer. It can be set as follows:
nil means consider only windows on the selected frame.
(Actually, the last frame used that is not a minibuffer-only frame.)
visible means consider windows on all visible frames.
t means consider windows on all frames. (Note that this value
is rarely the right thing to use—it might also return a tooltip frame.)
Note that the meaning of nil differs slightly from that of the
all-frames argument to next-window (see Cyclic Ordering of Windows).
A major client of this is display-buffer-reuse-window, but all
other action functions that try to reuse a window are affected as
well. display-buffer-in-previous-window consults it when
searching for a window that previously displayed the buffer on another
frame.
inhibit-switch-frame ¶A non-nil value prevents another frame from being raised or
selected, if the window chosen by display-buffer is displayed
there. Primarily affected by this are
display-buffer-use-some-frame and
display-buffer-reuse-window. Ideally,
display-buffer-pop-up-frame should be affected as well, but there
is no guarantee that the window manager will comply.
window-parameters ¶The value specifies an alist of window parameters to give the chosen window. All action functions that choose a window should process this entry.
window-min-width ¶The value specifies a minimum width of the window used, in canonical
frame columns. The special value full-width means the chosen
window should be one that has no other windows on the left or right of
it in its frame.
This entry is currently honored by display-buffer-use-some-window
and display-buffer-use-least-recent-window, which try hard to avoid
returning a less recently used window that does not satisfy the entry.
Note that providing such an entry alone does not necessarily make the
window as wide as specified by its value. To actually resize an
existing window or make a new window as wide as specified by this
entry’s value, a window-width entry specifying that value
should be provided as well. Such a window-width entry can,
however, specify a completely different value, or ask the window width
to fit that of its buffer, in which case the
window-min-width entry provides the guaranteed minimum width of
the window.
window-min-height ¶The value specifies a minimum height of the window used, in canonical
frame lines. The special value full-height means the chosen
window should be a full-height window, one that has no other windows
above or below it in its frame.
This entry is currently honored by display-buffer-below-selected
which does not use a window that is not as high as specified by this
entry. It’s also honored by display-buffer-use-some-window and
display-buffer-use-least-recent-window which try hard to avoid
returning a less recently used window if it does not satisfy this
constraint.
Note that providing such an entry alone does not necessarily make the
window as tall as specified by its value. To actually resize an
existing window or make a new window as tall as specified by that
value, a window-height entry specifying that value should be
provided as well. Such a window-height entry can, however,
specify a completely different value or ask the window height to be
fit to that of its buffer in which case the window-min-height
entry provides the guaranteed minimum height of the window used.
window-height ¶The value specifies whether and how to adjust the height of the chosen window and can be one of the following:
nil means to leave the height of the chosen window alone.
body-lines and whose CDR is an
integer that specifies the height of the chosen window’s body in frame
lines.
fit-window-to-buffer and
shrink-window-if-larger-than-buffer, see Resizing Windows.
By convention, the height of the chosen window is adjusted only if the window is part of a vertical combination (see Windows and Frames) to avoid changing the height of other, unrelated windows. Also, this entry should be processed only under certain conditions which are specified right below this list.
window-width ¶This entry is similar to the window-height entry described
before, but used to adjust the chosen window’s width instead. The
value can be one of the following:
nil means to leave the width of the chosen window alone.
body-columns and whose CDR is
an integer that specifies the width of the chosen window’s body in frame
columns.
window-size ¶This entry is a combination of the two preceding ones and can be used to
adjust the chosen window’s height and width. Since windows can
be resized in one direction only without affecting other windows,
window-size is effective only to set up the size of a window
appearing alone on a frame. The value can be one of the following:
nil means to leave the size of the chosen window alone.
body-chars and whose CDR
is a cons cell of two integers—the desired body width and height of
the chosen window in frame columns and lines. It’s effect is to adjust
the size of the frame accordingly.
This entry should be processed under only certain conditions which are specified right below this list.
dedicated ¶If non-nil, such an entry tells display-buffer to mark
any window it creates as dedicated to its buffer (see Dedicated Windows). It does that by calling set-window-dedicated-p with
the chosen window as first argument and the entry’s value as second.
Side windows are by default dedicated with the value side
(see Side Window Options and Functions).
preserve-size ¶If non-nil such an entry tells Emacs to preserve the size of
the window chosen (see Preserving Window Sizes). The value should
be either (t . nil) to preserve the width of the window,
(nil . t) to preserve its height or (t . t) to
preserve both, its width and its height. This entry should be
processed only under certain conditions which are specified right
after this list.
lru-frames ¶The value specifies the set of frames to search for a window that can be
used to display the buffer. It is honored by
display-buffer-use-some-window and
display-buffer-use-least-recent-window when trying to find a less
recently used window showing some other buffer. Its values are the same
as for the reusable-frames entry described above.
lru-time ¶The value is supposed to specify a use time (see Selecting Windows).
This entry is honored by display-buffer-use-some-window and
display-buffer-use-least-recent-window when trying to find a less
recently used window showing some other buffer. If a window’s use time
is higher than the value specified by this option, these action
functions will not consider such a window for displaying the buffer.
bump-use-time ¶If non-nil, such an entry will cause display-buffer to
bump the use time (see Selecting Windows) of the window it uses.
This should avoid later use of this window by action functions
like display-buffer-use-some-window and
display-buffer-use-least-recent-window for showing another
buffer.
There is a fine difference between using this entry and using the action
function display-buffer-use-least-recent-window. Calling the
latter means to only bump the use times of windows that function uses
for displaying the buffer. The entry described here will cause
display-buffer to bump the use time of any window used for
displaying a buffer.
pop-up-frame-parameters ¶The value specifies an alist of frame parameters to give a new frame,
if one is created. display-buffer-pop-up-frame is its one and
only addressee.
pop-up-frames ¶The value controls whether display-buffer may display buffers by
making new frames. It has the same meaning as the pop-up-frames
variable and takes precedence over it when present. Its main intended
purpose is to override a non-nil value of the variable for
particular buffers which the user prefers to keep in the selected frame.
parent-frame ¶The value specifies the parent frame to be used when the buffer is
displayed on a child frame. This entry is used only by
display-buffer-in-child-frame.
child-frame-parameters ¶The value specifies an alist of frame parameters to use when the buffer
is displayed on a child frame. This entry is used only by
display-buffer-in-child-frame.
side ¶The value denotes the side of the frame or window where a new window
displaying the buffer shall be created. This entry is used by
display-buffer-in-side-window to indicate the side of the frame
where a new side window shall be placed (see Displaying Buffers in Side Windows). It is also used by
display-buffer-in-atom-window to indicate the side of an
existing window where the new window shall be located (see Atomic Windows).
slot ¶If non-nil, the value specifies the slot of the side window
supposed to display the buffer. This entry is used only by
display-buffer-in-side-window.
direction ¶The value specifies a direction which, together with a window
entry, allows display-buffer-in-direction to determine the
location of the window to display the buffer.
window ¶The value specifies a window that is in some way related to the window
chosen by display-buffer. This entry is currently used by
display-buffer-in-atom-window to indicate the window on whose
side the new window shall be created. It is also used by
display-buffer-in-direction to specify the reference window on
whose side the resulting window shall appear.
allow-no-window ¶If the value is non-nil, display-buffer does not
necessarily have to display the buffer and the caller is prepared to
accept that. This entry is not intended for user customizations,
since there is no guarantee that an arbitrary caller of
display-buffer will be able to handle the case that no window
will display the buffer. display-buffer-no-window is the only
action function that cares about this entry.
some-window ¶If the value is nil or lru, display-buffer-use-some-window
prefers the least recently used window while avoiding selecting windows
that are not full-width and windows on another frame. If the value is
mru, it prefers the most recently used window not considering the
selected window and windows on any frame but the selected one. If the
value is a function, it is called with two arguments: a buffer and an
alist, and should return the window where to display the buffer.
body-function ¶The value must be a function taking one argument (a displayed window).
This function can be used to fill the displayed window’s body with
some contents that might depend on dimensions of the displayed window.
It is called after the buffer is displayed, and before
the entries window-height, window-width and
preserve-size are applied that could resize the window to fit
it to the inserted contents.
post-command-select-window ¶If the value is non-nil, the buffer displayed by display-buffer
is selected after the current command is executed by running the hook
post-command-hook (see 命令循环概述).
If the value is nil, the buffer selected by such functions as
pop-to-buffer is deselected, and the window that was selected
before calling this function will remain selected regardless of which
windows were selected afterwards within this command.
category ¶If the caller of display-buffer passes an alist entry
(category . symbol) in its action argument, then you
can match the displayed buffer by using the same category symbol in the
condition part of display-buffer-alist entries. See buffer-match-p. Thus, if a Lisp program uses a particular
symbol as the category when calling display-buffer, users
can customize how these buffers will be displayed by including such an
entry in display-buffer-alist.
By convention, the entries window-height, window-width
and preserve-size are applied after the chosen window’s buffer
has been set up and if and only if that window never showed another
buffer before. More precisely, the latter means that the window must
have been either created by the current display-buffer call or
the window was created earlier by display-buffer to show the
buffer and never was used to show another buffer until it was reused
by the current invocation of display-buffer.
If no window-height, window-width or window-size
entry was specified, the window may still be resized automatically when
the buffer is temporary and temp-buffer-resize-mode has been
enabled, Temporary Displays. In that case, the CDR of a
window-height, window-width or window-size entry
can be used to inhibit or override the default behavior of
temp-buffer-resize-mode for specific buffers or invocations of
display-buffer.
The behavior of buffer display actions (see Choosing a Window for Displaying a Buffer) can be further modified by the following user options.
If the value of this variable is non-nil, display-buffer
is allowed to split an existing window to make a new window for
displaying in. This is the default.
This variable is provided for backward compatibility only. It is
obeyed by display-buffer via a special mechanism in
display-buffer-fallback-action, which calls the action function
display-buffer-pop-up-window (see Action Functions for Buffer Display) when the value of this option is non-nil. It is
not consulted by display-buffer-pop-up-window itself, which the
user may specify directly in display-buffer-alist etc.
This variable specifies a function for splitting a window, in order to
make a new window for displaying a buffer. It is used by the
display-buffer-pop-up-window action function to actually split
the window.
The value must be a function that takes one argument, a window, and
returns either a new window (which will be used to display the desired
buffer) or nil (which means the splitting failed). The default
value is split-window-sensibly, which is documented next.
This function tries to split window and return the newly created
window. If window cannot be split, it returns nil. If
window is omitted or nil, it defaults to the selected
window.
This function obeys the usual rules that determine when a window may
be split (see Splitting Windows). It first tries to split by
placing the new window below, subject to the restriction imposed by
split-height-threshold (see below), in addition to any other
restrictions. If that fails, it tries to split by placing the new
window to the right, subject to split-width-threshold (see
below). If that also fails, and the window is the only window on its
frame, this function again tries to split and place the new window
below, disregarding split-height-threshold. If this fails as
well, this function gives up and returns nil.
This variable specifies whether split-window-sensibly is
allowed to split the window placing the new window below. If it is an
integer, that means to split only if the original window has at least
that many lines. If it is nil, that means not to split this
way.
This variable specifies whether split-window-sensibly is
allowed to split the window placing the new window to the right. If
the value is an integer, that means to split only if the original
window has at least that many columns. If the value is nil,
that means not to split this way.
This variable, if non-nil, causes display-buffer to even
window sizes whenever it reuses an existing window, and that window is
adjacent to the selected one.
If its value is width-only, sizes are evened only if the reused
window is on the left or right of the selected one and the selected
window is wider than the reused one. If its value is height-only
sizes are evened only if the reused window is above or beneath the
selected window and the selected window is higher than the reused one.
Any other non-nil value means to even sizes in any of these cases
provided the selected window is larger than the reused one in the sense
of their combination.
If the value of this variable is non-nil, that means
display-buffer may display buffers by making new frames. The
default is nil.
A non-nil value also means that when display-buffer is
looking for a window already displaying buffer-or-name, it can
search any visible or iconified frame, not just the selected frame.
An entry by the same name in display-buffer’s alist
takes precedence over the variable.
This variable is provided mainly for backward compatibility. It is
obeyed by display-buffer via a special mechanism in
display-buffer-fallback-action, which calls the action function
display-buffer-pop-up-frame (see Action Functions for Buffer Display) if the value is non-nil. (This is done before
attempting to split a window.) This variable is not consulted by
display-buffer-pop-up-frame itself, which the user may specify
directly in display-buffer-alist etc.
This variable specifies a function for creating a new frame, in order
to make a new window for displaying a buffer. It is used by the
display-buffer-pop-up-frame action function.
The value should be a function that takes no arguments and returns a
frame, or nil if no frame could be created. The default value
is a function that creates a frame using the parameters specified by
pop-up-frame-alist (see below).
This variable holds an alist of frame parameters (see Frame Parameters), which is used by the function specified by
pop-up-frame-function to make a new frame. The default is
nil.
This option is provided for backward compatibility only. Note, that
when display-buffer-pop-up-frame calls the function specified
by pop-up-frame-function, it prepends the value of all
pop-up-frame-parameters action alist entries to
pop-up-frame-alist so that the values specified by the action
alist entry effectively override any corresponding values of
pop-up-frame-alist.
Hence, users should set up a pop-up-frame-parameters action
alist entry in display-buffer-alist instead of customizing
pop-up-frame-alist. Only this will guarantee that the value of
a parameter specified by the user overrides the value of that
parameter specified by the caller of display-buffer.
Many efforts in the design of display-buffer have been given
to maintain compatibility with code that uses older options like
pop-up-windows, pop-up-frames,
pop-up-frame-alist, same-window-buffer-names and
same-window-regexps. Lisp Programs and users should refrain
from using these options. Above we already warned against customizing
pop-up-frame-alist. Here we describe how to convert the
remaining options to use display actions instead.
pop-up-windows ¶This variable is t by default. Instead of customizing it to
nil and thus telling display-buffer what not to do, it’s
much better to list in display-buffer-base-action the action
functions it should try instead as, for example:
(setopt
display-buffer-base-action
'((display-buffer-reuse-window display-buffer-same-window
display-buffer-in-previous-window
display-buffer-use-some-window)))
pop-up-frames ¶Instead of customizing this variable to t, you can customize
display-buffer-base-action, for example, as follows:
(setopt display-buffer-base-action '(nil (pop-up-frames . t)))
same-window-buffer-names ¶same-window-regexpsInstead of adding a buffer name or a regular expression to one of
these options use a display-buffer-alist entry for that buffer
specifying the action function display-buffer-same-window.
(setopt
display-buffer-alist
(cons '("\\*foo\\*" (display-buffer-same-window))
display-buffer-alist))
From the past subsections we already know that display-buffer
must be supplied with a number of display actions (see Choosing a Window for Displaying a Buffer) in order to display a buffer. In a completely uncustomized
Emacs, these actions are specified by
display-buffer-fallback-action in the following order of
precedence: Reuse a window, pop up a new window on the same frame, use
a window previously showing the buffer, use some window and pop up a
new frame. (Note that the remaining actions named by
display-buffer-fallback-action are void in an uncustomized
Emacs).
Consider the following form:
(display-buffer (get-buffer-create "*foo*"))
Evaluating this form in the buffer *scratch* of an uncustomized
Emacs session will usually fail to reuse a window that shows
*foo* already, but succeed in popping up a new window.
Evaluating the same form again will now not cause any visible
changes—display-buffer reused the window already showing
*foo* because that action was applicable and had the highest
precedence among all applicable actions.
Popping up a new window will fail if there is not enough space on
the selected frame. In an uncustomized Emacs it typically fails when
there are already two windows on a frame. For example, if you now
type C-x 1 followed by C-x 2 and evaluate the form
once more, *foo* should show up in the lower
window—display-buffer just used “some” window. If, before
typing C-x 2 you had typed C-x o, *foo*
would have been shown in the upper window because “some” window
stands for the “least recently used” window and the selected window
has been least recently used if and only if it is alone on its frame.
Let’s assume you did not type C-x o and *foo* is shown in the lower window. Type C-x o to get there followed by C-x left and evaluate the form again. This should display *foo* in the same, lower window because that window had already shown *foo* previously and was therefore chosen instead of some other window.
So far we have only observed the default behavior in an uncustomized
Emacs session. To see how this behavior can be customized, let’s
consider the option display-buffer-base-action. It provides a
very coarse customization which conceptually affects the display of
any buffer. It can be used to supplement the actions supplied
by display-buffer-fallback-action by reordering them or by
adding actions that are not present there but fit more closely the
user’s editing practice. However, it can also be used to change the
default behavior in a more profound way.
Let’s consider a user who, as a rule, prefers to display buffers on another frame. Such a user might provide the following customization:
(setopt display-buffer-base-action '((display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . 0)))
This setting will cause display-buffer to first try to find a
window showing the buffer on a visible or iconified frame and, if no
such frame exists, pop up a new frame. You can observe this behavior
on a graphical system by typing C-x 1 in the window showing
*scratch* and evaluating our canonical display-buffer
form. This will usually create (and give focus to) a new frame whose
root window shows *foo*. Iconify that frame and evaluate the
canonical form again: display-buffer will reuse the window on
the new frame (usually raising the frame and giving it focus too).
Only if creating a new frame fails, display-buffer will
apply the actions supplied by display-buffer-fallback-action
which means to again try reusing a window, popping up a new window and
so on. A trivial way to make frame creation fail is supplied by the
following form:
(let ((pop-up-frame-function 'ignore)) (display-buffer (get-buffer-create "*foo*")))
We will forget about that form immediately after observing that it fails to create a new frame and uses a fallback action instead.
Note that display-buffer-reuse-window appears redundant in
the customization of display-buffer-base-action because it is
already part of display-buffer-fallback-action and should be
tried there anyway. However, that would fail because due to the
precedence of display-buffer-base-action over
display-buffer-fallback-action, at that time
display-buffer-pop-up-frame would have already won the race.
In fact, this:
(setopt display-buffer-base-action '(display-buffer-pop-up-frame (reusable-frames . 0)))
would cause display-buffer to always pop up a new frame
which is probably not what our user wants.
So far, we have only shown how users can customize the
default behavior of display-buffer. Let us now see how
applications can change the course of display-buffer.
The canonical way to do that is to use the action argument of
display-buffer or a function that calls it, like, for example,
pop-to-buffer (see Switching to a Buffer in a Window).
Suppose an application wants to display *foo* preferably below the selected window (to immediately attract the attention of the user to the new window) or, if that fails, in a window at the bottom of the frame. It could do that with a call like this:
(display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom)))
In order to see how this new, modified form works, delete any frame
showing *foo*, type C-x 1 followed by C-x 2 in the
window showing *scratch*, and subsequently evaluate that form.
display-buffer should split the upper window, and show
*foo* in the new window. Alternatively, if after C-x 2
you had typed C-x o, display-buffer would have split the
window at the bottom instead.
Suppose now that, before evaluating the new form, you have made the
selected window as small as possible, for example, by evaluating the
form (fit-window-to-buffer) in that window. In that case,
display-buffer would have failed to split the selected window
and would have split the frame’s root window instead, effectively
displaying *foo* at the bottom of the frame.
In either case, evaluating the new form a second time should reuse the window already showing *foo* since both functions supplied by the action argument try to reuse such a window first.
By setting the action argument, an application effectively
overrules any customization of display-buffer-base-action. Our
user can now either accept the choice of the application, or redouble
by customizing the option display-buffer-alist as follows:
(setopt
display-buffer-alist
'(("\\*foo\\*"
(display-buffer-reuse-window display-buffer-pop-up-frame))))
Trying this with the new, modified form above in a configuration that
does not show *foo* anywhere, will display *foo* on a
separate frame, completely ignoring the action argument of
display-buffer.
Note that we didn’t care to specify a reusable-frames action
alist entry in our specification of display-buffer-alist.
display-buffer always takes the first one it finds—in our
case the one specified by display-buffer-base-action. If we
wanted to use a different specification, for example, to exclude
iconified frames showing *foo* from the list of reusable ones,
we would have to specify that separately, however:
(setopt
display-buffer-alist
'(("\\*foo\\*"
(display-buffer-reuse-window display-buffer-pop-up-frame)
(reusable-frames . visible))))
If you try this, you will notice that repeated attempts to display *foo* will succeed to reuse a frame only if that frame is visible.
The above example would allow the conclusion that users customize
display-buffer-alist for the sole purpose to overrule the
action argument chosen by applications. Such a conclusion would
be incorrect. display-buffer-alist is the standard option for
users to direct the course of display of specific buffers in a
preferred way regardless of whether the display is also guided by an
action argument.
We can, however, reasonably conclude that customizing
display-buffer-alist differs from customizing
display-buffer-base-action in two major aspects: it is stronger
because it overrides the action argument of
display-buffer, and it enables you to explicitly specify the
affected buffers. In fact, displaying other buffers is not affected
in any way by a customization for *foo*. For example,
(display-buffer (get-buffer-create "*bar*"))
continues being governed by the settings of
display-buffer-base-action and
display-buffer-fallback-action only.
We could stop with our examples here but Lisp programs still have
an ace up their sleeves which they can use to overrule any
customization of display-buffer-alist. It’s the variable
display-buffer-overriding-action which they can bind around
display-buffer calls as follows:
(let ((display-buffer-overriding-action
'((display-buffer-same-window))))
(display-buffer
(get-buffer-create "*foo*")
'((display-buffer-below-selected display-buffer-at-bottom))))
Evaluating this form will usually display *foo* in the selected window regardless of the action argument and any user customizations. (Usually, an application will not bother to also provide an action argument. Here it just serves to illustrate the fact that it gets overridden.)
It might be illustrative to look at the list of action functions
display-buffer would have tried to display *foo* with
the customizations we provided here. The list (including comments
explaining who added this and the subsequent elements) is:
(display-buffer-same-window ;; `display-buffer-overriding-action' display-buffer-reuse-window ;; `display-buffer-alist' display-buffer-pop-up-frame display-buffer-below-selected ;; ACTION argument display-buffer-at-bottom display-buffer-reuse-window ;; `display-buffer-base-action' display-buffer-pop-up-frame display-buffer--maybe-same-window ;; `display-buffer-fallback-action' display-buffer-reuse-window display-buffer--maybe-pop-up-frame-or-window display-buffer-in-previous-window display-buffer-use-some-window display-buffer-pop-up-frame)
Note that among the internal functions listed here,
display-buffer--maybe-same-window is effectively ignored while
display-buffer--maybe-pop-up-frame-or-window actually runs
display-buffer-pop-up-window.
The action alist passed in each function call is:
((reusable-frames . visible) (reusable-frames . 0))
which shows that we have used the second specification of
display-buffer-alist above, overriding the specification
supplied by display-buffer-base-action. Suppose our user had
written that as
(setopt
display-buffer-alist
'(("\\*foo\\*"
(display-buffer-reuse-window display-buffer-pop-up-frame)
(inhibit-same-window . t)
(reusable-frames . visible))))
In this case the inhibit-same-window alist entry will
successfully invalidate the display-buffer-same-window
specification from display-buffer-overriding-action and
display-buffer will show *foo* on another frame. To
make display-buffer-overriding-action more robust in this
regard, the application would have to specify an appropriate
inhibit-same-window entry too, for example, as follows:
(let ((display-buffer-overriding-action
'(display-buffer-same-window (inhibit-same-window . nil))))
(display-buffer (get-buffer-create "*foo*")))
This last example shows that while the precedence order of action functions is fixed, as described in Choosing a Window for Displaying a Buffer, an action alist entry specified by a display action ranked lower in that order can affect the execution of a higher ranked display action.
In its most simplistic form, a frame accommodates always one single
window that can be used for displaying a buffer. As a consequence, it
is always the latest call of display-buffer that will have
succeeded in placing its buffer there.
Since working with such a frame is not very practical, Emacs by
default allows for more complex frame layouts controlled by the
default values of the frame size and the split-height-threshold
and split-width-threshold options. Displaying a buffer not yet
shown on a frame then either splits the single window on that frame or
(re-)uses one of its two windows.
The default behavior is abandoned as soon as the user customizes
one of these thresholds or manually changes the frame’s layout. The
default behavior is also abandoned when calling display-buffer
with a non-nil action argument or the user customizes one
of the options mentioned in the previous subsections. Mastering
display-buffer soon may become a frustrating experience due to
the plethora of applicable display actions and the resulting frame
layouts.
However, refraining from using buffer display functions and falling back on a split & delete windows metaphor is not a good idea either. Buffer display functions give Lisp programs and users a framework to reconcile their different needs; no comparable framework exists for splitting and deleting windows. Buffer display functions also allow to at least partially restore the layout of a frame when removing a buffer from it later (see Quitting Windows).
Below we will give a number of guidelines to redeem the frustration mentioned above and thus to avoid literally losing buffers in-between the windows of a frame.
Writing display actions can be a pain because one has to lump together
action functions and action alists in one huge list. (Historical
reasons prevented us from having display-buffer support
separate arguments for these.) It might help to memorize some basic
forms like the ones listed below:
'(nil (inhibit-same-window . t))
specifies an action alist entry only and no action function. Its sole
purpose is to inhibit a display-buffer-same-window function
specified elsewhere from showing the buffer in the same window, see
also the last example of the preceding subsection.
'(display-buffer-below-selected)
on the other hand, specifies one action function and an empty action alist. To combine the effects of the above two specifications one would write the form
'(display-buffer-below-selected (inhibit-same-window . t))
to add another action function one would write
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t))
and to add another alist entry one would write
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer))
That last form can be used as action argument of
display-buffer in the following way:
(display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer)))
In a customization of display-buffer-alist it would be used as
follows:
(setopt
display-buffer-alist
'(("\\*foo\\*"
(display-buffer-below-selected display-buffer-at-bottom)
(inhibit-same-window . t)
(window-height . fit-window-to-buffer))))
To add a customization for a second buffer one would then write:
(setopt
display-buffer-alist
'(("\\*foo\\*"
(display-buffer-below-selected display-buffer-at-bottom)
(inhibit-same-window . t)
(window-height . fit-window-to-buffer))
("\\*bar\\*"
(display-buffer-reuse-window display-buffer-pop-up-frame)
(reusable-frames . visible))))
display-buffer-alist and display-buffer-base-action are
user options—Lisp programs must never set or rebind them.
display-buffer-overriding-action, on the other hand, is
reserved for applications—who seldom use that option and if they use
it, then with utmost care.
Older implementations of display-buffer frequently caused
users and applications to fight over the settings of user options like
pop-up-frames and pop-up-windows (see Additional Options for Displaying Buffers). This was one major reason for redesigning
display-buffer—to provide a clear framework specifying what
users and applications should be allowed to do.
Lisp programs must be prepared that user customizations may
cause buffers to get displayed in an unexpected way. They should
never assume in their subsequent behavior, that the buffer has been
shown precisely the way they asked for in the action argument of
display-buffer.
Users should not pose too many and too severe restrictions on how
arbitrary buffers get displayed. Otherwise, they will risk to lose
the characteristics of showing a buffer for a certain purpose.
Suppose a Lisp program has been written to compare different versions
of a buffer in two windows side-by-side. If the customization of
display-buffer-alist prescribes that any such buffer should be
always shown in or below the selected window, the program will have a
hard time to set up the desired window configuration via
display-buffer.
To specify a preference for showing an arbitrary buffer, users
should customize display-buffer-base-action. An example of how
users who prefer working with multiple frames would do that was given
in the previous subsection. display-buffer-alist should be
reserved for displaying specific buffers in a specific way.
Generally, it’s always a good idea for users and Lisp
programmers to be prepared for the case that a window already shows
the buffer in question and to reuse that window. In the preceding
subsection we have shown that failing to do so properly may cause
display-buffer to continuously pop up a new frame although a
frame showing that buffer existed already. In a few cases only, it
might be undesirable to reuse a window, for example, when a different
portion of the buffer should be shown in that window.
Hence, display-buffer-reuse-window is one action function
that should be used as often as possible, both in action
arguments and customizations. An inhibit-same-window entry in
the action argument usually takes care of the most common case
where reusing a window showing the buffer should be avoided—that
where the window in question is the selected one.
This is a no-brainer for people working with multiple frames—the
frame showing the buffer will automatically raise and get focus unless
an inhibit-switch-frame entry forbids it. For single frame
users this task can be considerably more difficult. In particular,
display-buffer-pop-up-window and
display-buffer-use-some-window can become obtrusive in this
regard. They split or use a seemingly arbitrary (often the largest or
least recently used) window, distracting the user’s attention.
Some Lisp programs therefore try to choose a window at the bottom of
the frame, for example, in order to display the buffer in vicinity of
the minibuffer window where the user is expected to answer a question
related to the new window. For non-input related actions
display-buffer-below-selected might be preferable because the
selected window usually already has the user’s attention.
Many applications call display-buffer from within window
excursions produced by with-selected-window or
select-window calls with a non-nil norecord
argument. This is almost always a bad idea because the window selected
within such an excursion is usually not the window selected in the
configuration presented to the user.
If, for example, a user had added an inhibit-same-window alist
entry, that entry would have avoided the window selected within the
scope of the excursion and not the window selected in the resulting
configuration. Even if no such entry has been added, the resulting
behavior might be strange. While in a frame containing one live
window, evaluating the following form
(progn (split-window) (display-buffer "*Messages*"))
will display a window showing the *Messages* buffer at the bottom and leave the other window selected. Evaluating the next form
(with-selected-window (split-window) (display-buffer "*Messages*"))
will display *Messages* in a window on the top and select it
which is usually not what display-buffer is supposed to do.
On the other hand, while evaluating the following form
(progn (split-window) (pop-to-buffer "*Messages*"))
will correctly select the *Messages* buffer, the next form
(progn
(split-window)
(with-selected-window (selected-window)
(pop-to-buffer "*Messages*")))
will not.
Also, invocations of action functions like
display-buffer-use-some-window and
display-buffer-use-least-recent-window that expect the selected
window to have the highest use time among all windows, may fail to
produce a window according to their specifications.
Hence, an application that relies on using a window excursion should try
to postpone the display-buffer call until after the excursion has
terminated.
Each window remembers in a list the buffers it has previously
displayed, and the order in which these buffers were removed from it.
This history is used, for example, by replace-buffer-in-windows
(see Buffers and Windows), and when quitting windows
(see Quitting Windows). The list is automatically maintained by
Emacs, but you can use the following functions to explicitly inspect
or alter it:
This function returns a list specifying the previous contents of window. The optional argument window should be a live window and defaults to the selected one.
Each list element has the form (buffer window-start
window-pos), where buffer is a buffer previously shown in
the window, window-start is the window start position
(see The Window Start and End Positions) when that buffer was last shown, and
window-pos is the point position (see Windows and Point) when
that buffer was last shown in window.
The list is ordered so that earlier elements correspond to more recently-shown buffers, and the first element usually corresponds to the buffer most recently removed from the window.
This function sets window’s previous buffers to the value of
prev-buffers. The argument window must be a live window
and defaults to the selected one. The argument prev-buffers
should be a list of the same form as that returned by
window-prev-buffers.
In addition, each window maintains a list of next buffers, which
is a list of buffers re-shown by switch-to-prev-buffer (see
below). This list is mainly used by switch-to-prev-buffer and
switch-to-next-buffer for choosing buffers to switch to.
This function returns the list of buffers recently re-shown in
window via switch-to-prev-buffer. The window
argument must denote a live window or nil (meaning the selected
window).
This function sets the next buffer list of window to
next-buffers. The window argument should be a live window
or nil (meaning the selected window). The argument
next-buffers should be a list of buffers.
The following commands can be used to cycle through the global buffer
list, much like bury-buffer and unbury-buffer. However,
they cycle according to the specified window’s history list, rather
than the global buffer list. In addition, they restore
window-specific window start and point positions, and may show a
buffer even if it is already shown in another window. The
switch-to-prev-buffer command, in particular, is used by
replace-buffer-in-windows, bury-buffer and
quit-window to find a replacement buffer for a window.
This command displays the previous buffer in window. The
argument window should be a live window or nil (meaning
the selected window). If the optional argument bury-or-kill is
non-nil, this means that the buffer currently shown in
window is about to be buried or killed and consequently should
not be switched to in future invocations of this command.
The previous buffer is usually the buffer shown before the buffer
currently shown in window. However, a buffer that has been buried
or killed, or has been already shown by a recent invocation of
switch-to-prev-buffer, does not qualify as previous buffer.
If repeated invocations of this command have already shown all buffers previously shown in window, further invocations will show buffers from the buffer list of the frame window appears on (see The Buffer List).
The option switch-to-prev-buffer-skip described below can be
used to inhibit switching to certain buffers, for example, to those
already shown in another window. Also, if window’s frame has a
buffer-predicate parameter (see Buffer Parameters), that
predicate may inhibit switching to certain buffers.
This command switches to the next buffer in window, thus undoing
the effect of the last switch-to-prev-buffer command in
window. The argument window must be a live window and
defaults to the selected one.
If there is no recent invocation of switch-to-prev-buffer that
can be undone, this function tries to show a buffer from the buffer list
of the frame window appears on (see The Buffer List).
The option switch-to-prev-buffer-skip and the
buffer-predicate (see Buffer Parameters) of window’s
frame affect this command as they do for switch-to-prev-buffer.
By default switch-to-prev-buffer and
switch-to-next-buffer can switch to a buffer that is already
shown in another window. The following option can be used to override
this behavior.
If this variable is nil, switch-to-prev-buffer may
switch to any buffer, including those already shown in other windows.
If this variable is non-nil, switch-to-prev-buffer will
refrain from switching to certain buffers. The following values can
be used:
this means do not switch to a buffer shown on the frame that
hosts the window switch-to-prev-buffer is acting upon.
visible means do not switch to a buffer shown on any visible
frame.
t means do not switch to a buffer shown on any live frame.
switch-to-prev-buffer, a buffer switch-to-prev-buffer
intends to switch to and the bury-or-kill argument of
switch-to-prev-buffer. If that function returns
non-nil, switch-to-prev-buffer will refrain from
switching to the buffer specified by the second argument.
The command switch-to-next-buffer obeys this option in a
similar way. If this option specifies a function,
switch-to-next-buffer will call that function with the third
argument always nil.
Note that since switch-to-prev-buffer is called by
bury-buffer, replace-buffer-in-windows and
quit-restore-window as well, customizing this option may also
affect the behavior of Emacs when a window is quit or a buffer gets
buried or killed.
Note also that under certain circumstances
switch-to-prev-buffer and switch-to-next-buffer may
ignore this option, for example, when there is only one buffer left
these functions can switch to.
This user option should be either a regular expression or a list of
regular expressions. Buffers whose names match one of those regular
expressions will be ignored by switch-to-prev-buffer and
switch-to-next-buffer (except when there’s no other buffer to
switch to).
Functions for displaying a buffer can be told to not use specific
windows by marking these windows as dedicated to their buffers.
display-buffer (see Choosing a Window for Displaying a Buffer) never uses a dedicated
window for displaying another buffer in it. get-lru-window and
get-largest-window (see Cyclic Ordering of Windows) do not
consider dedicated windows as candidates when their dedicated
argument is non-nil. The behavior of set-window-buffer
(see Buffers and Windows) with respect to dedicated windows is
slightly different, see below.
Functions supposed to remove a buffer from a window or a window from
a frame can behave specially when a window they operate on is dedicated.
We will distinguish four basic cases, namely where (1) the window is
not the only window on its frame, (2) the window is the only window on
its frame but there are other frames on the same terminal left, (3)
the window is the only window on the only frame on the same terminal,
and (4) the dedication’s value is side
(see Displaying Buffers in Side Windows).
In particular, delete-windows-on (see Deleting Windows)
handles case (2) by deleting the associated frame and cases (3) and (4)
by showing another buffer in that frame’s only window. The function
replace-buffer-in-windows (see Buffers and Windows) which is
called when a buffer gets killed, deletes the window in case (1) and
behaves like delete-windows-on otherwise.
When bury-buffer (see The Buffer List) operates on the
selected window (which shows the buffer that shall be buried), it
handles case (2) by calling frame-auto-hide-function
(see Quitting Windows) to deal with the selected frame. The other
two cases are handled as with replace-buffer-in-windows.
This function returns non-nil if window is dedicated to its
buffer and nil otherwise. More precisely, the return value is
the value assigned by the last call of set-window-dedicated-p for
window, or nil if that function was never called with
window as its argument. The default for window is the
selected window.
This function marks window as dedicated to its buffer if
flag is non-nil, and non-dedicated otherwise.
Interactively you can use the C-x w d
(toggle-window-dedicated) command to do the same.
As a special case, if flag is t, window becomes
strongly dedicated to its buffer. set-window-buffer
signals an error when the window it acts upon is strongly dedicated to
its buffer and does not already display the buffer it is asked to
display. Other functions do not treat t differently from any
non-nil value.
You can also tell display-buffer to mark a window it creates as
dedicated to its buffer by providing a suitable dedicated
action alist entry (see Action Alists for Buffer Display).
After a command uses display-buffer to put a buffer on the
screen, the user may decide to hide it and return to the previous
configuration of the Emacs display. We call that quitting the
window. The way to do this is to call quit-window while the
window used by display-buffer is the selected window.
The right way to restore the previous configuration of the display depends on what was done to the window where the buffer now appears. It might be right to delete that window, or delete its frame, or just display another buffer in that window. One complication is that the user may have changed the window configuration since the act of displaying that buffer, and it would be undesirable to undo the user’s explicitly requested changes.
To enable quit-window to do the right thing,
display-buffer saves information about what it did in the
window’s quit-restore parameter (see Window Parameters).
This command quits window and buries its buffer. The argument
window must be a live window and defaults to the selected one.
With prefix argument kill non-nil, it kills the buffer
instead of burying it.
The function quit-window first runs quit-window-hook.
Then it calls the function quit-restore-window, described next,
which does the hard work.
You can get more control by calling quit-restore-window instead.
This function handles window and its buffer after quitting. The
optional argument window must be a live window and defaults to
the selected one. The function takes account of the window’s
quit-restore parameter.
The optional argument bury-or-kill specifies how to deal with window’s buffer. The following values are meaningful:
nilThis means to not deal with the buffer in any particular way. As a
consequence, if window is not deleted, invoking
switch-to-prev-buffer will usually show the buffer again.
appendThis means that if window is not deleted, its buffer is moved to
the end of window’s list of previous buffers (see Window History), so it’s less likely that future invocations of
switch-to-prev-buffer will switch to it. Also, it moves the
buffer to the end of the frame’s buffer list (see The Buffer List).
buryThis means that if window is not deleted, its buffer is removed
from window’s list of previous buffers. Also, it moves the
buffer to the end of the frame’s buffer list. This is the most
reliable way to prevent switch-to-prev-buffer from switching to
this buffer again, short of killing the buffer.
killThis means to kill window’s buffer.
The argument bury-or-kill also specifies what to do with
window’s frame when window should be deleted, if it is the
only window on its frame, and there are other frames on that frame’s
terminal. If bury-or-kill equals kill, it means to
delete the frame. Otherwise, the fate of the frame is determined by
calling frame-auto-hide-function (see below) with that frame as
sole argument.
This function always sets window’s quit-restore parameter
to nil unless it deletes the window.
The window window’s quit-restore parameter (see Window Parameters) should be nil or a list of four elements:
(method obuffer owindow this-buffer)
The first element, method, is one of the four symbols
window, frame, same and other.
frame and window control how to delete window,
while same and other control displaying some other
buffer in it.
Specifically, window means that the window has been specially
created by display-buffer; frame means that a separate
frame has been created; same, that the window has only ever
displayed this buffer; other, that the window showed another
buffer before.
The second element, obuffer, is either one of the symbols
window or frame, or a list of the form
(prev-buffer prev-window-start prev-window-point height)
which says which buffer was shown in window before, that buffer’s window start (see The Window Start and End Positions) and window point (see Windows and Point) positions at that time, and window’s height at that time. If prev-buffer is still live when quitting window, quitting the window may reuse window to display prev-buffer.
The third element, owindow, is the window that was selected just before the displaying was done. If quitting deletes window, it tries to select owindow.
The fourth element, this-buffer, is the buffer whose displaying
set the quit-restore parameter. Quitting window may delete
that window only if it still shows that buffer.
Quitting window tries to delete it if and only if (1)
method is either window or frame, (2) the window
has no history of previously-displayed buffers and (3)
this-buffer equals the buffer currently displayed in
window. If window is part of an atomic window
(see Atomic Windows), quitting will try to delete the root of that
atomic window instead. In either case, it tries to avoid signaling an
error when window cannot be deleted.
If obuffer is a list, and prev-buffer is still live, quitting displays prev-buffer in window according to the rest of the elements of obuffer. This includes resizing the window to height if it was temporarily resized to display this-buffer.
Otherwise, if window was previously used for displaying other buffers (see Window History), the most recent buffer in that history will be displayed.
The following option specifies a function to do the right thing with a frame containing one window when quitting that window.
The function specified by this option is called to automatically hide frames. This function is called with one argument—a frame.
The function specified here is called by bury-buffer
(see The Buffer List) when the selected window is dedicated and shows
the buffer to bury. It is also called by quit-restore-window
(see above) when the frame of the window to quit has been specially
created for displaying that window’s buffer and the buffer is not
killed.
The default is to call iconify-frame (see Visibility of Frames). Alternatively, you may specify either delete-frame
(see Deleting Frames) to remove the frame from its display,
make-frame-invisible to make the frame invisible, ignore
to leave the frame unchanged, or any other function that can take a
frame as its sole argument.
Note that the function specified by this option is called only if the specified frame contains just one live window and there is at least one other frame on the same terminal.
For a particular frame, the value specified here may be overridden by
that frame’s auto-hide-function frame parameter (see Frame Interaction Parameters).
Side windows are special windows positioned at any of the four sides of a frame’s root window (see Windows and Frames). In practice, this means that the area of the frame’s root window is subdivided into a main window and a number of side windows surrounding that main window. The main window is either a “normal” live window or specifies the area containing all the normal windows.
In their most simple form of use, side windows allow displaying
specific buffers always in the same area of a frame. Hence they can
be regarded as a generalization of the concept provided by
display-buffer-at-bottom (see Action Functions for Buffer Display) to the remaining sides of a frame. With suitable
customizations, however, side windows can be also used to provide
frame layouts similar to those found in so-called integrated
development environments (IDEs).
The following action function for display-buffer (see Action Functions for Buffer Display) creates or reuses a side window for
displaying the specified buffer.
This function displays buffer in a side window of the selected
frame. It returns the window used for displaying buffer,
nil if no such window can be found or created.
alist is an association list of symbols and values as for
display-buffer. The following symbols in alist are special
for this function:
sideDenotes the side of the frame where the window shall be located. Valid
values are left, top, right and bottom. If
unspecified, the window is located at the bottom of the frame.
slotDenotes a slot at the specified side where to locate the window. A
value of zero means to preferably position the window in the middle of
the specified side. A negative value means to use a slot preceding
(that is, above or on the left of) the middle slot. A positive value
means to use a slot following (that is, below or on the right of) the
middle slot. Hence, all windows on a specific side are ordered by their
slot value. If unspecified, the window is located in the middle
of the specified side.
dedicatedThe dedicated flag (see Dedicated Windows) has a slightly different
meaning for side windows. When a side window is created, that flag is
set to the value side to prevent display-buffer to use the
window in other action functions. Its value persists across invocations
of quit-window, kill-buffer, previous-buffer and
next-buffer.
In particular, these commands will refrain from showing, in a side
window, buffers that have not been displayed in that window before.
They will also refrain from having a normal, non-side window show a
buffer that has been already displayed in a side window. A notable
exception to the latter rule occurs when an application, after
displaying a buffer, resets that buffer’s local variables. To override
these rules and always delete a side window with quit-window or
kill-buffer, and eventually prevent the use of
previous-buffer and next-buffer, set this value to
t or specify a value via display-buffer-mark-dedicated.
If you specify the same slot on the same side for two or more different buffers, the buffer displayed last is shown in the corresponding window. Hence, slots can be used for sharing the same side window between buffers.
This function installs the window-side and window-slot
parameters (see Window Parameters) and makes them persistent. It
does not install any other window parameters unless they have been
explicitly provided via a window-parameters entry in alist.
By default, side windows cannot be split via split-window
(see Splitting Windows). Also, a side window is not reused or
split by any buffer display action (see Action Functions for Buffer Display) unless it is explicitly specified as target of that
action. Note also that delete-other-windows cannot make a side
window the only window on its frame (see Deleting Windows).
The following options provide additional control over the placement of side windows.
If non-nil, the side windows on the left and right of a frame
occupy the frame’s full height. Otherwise, the side windows on the top
and bottom of the frame occupy the frame’s full width.
This option specifies the maximum number of side windows on each side of
a frame. The value is a list of four elements specifying the number of
side window slots on (in this order) the left, top, right and bottom of
each frame. If an element is a number, it means to display at most that
many windows on the corresponding side. If an element is nil, it
means there’s no bound on the number of slots on that side.
If any of the specified values is zero, no window can be created on the
corresponding side. display-buffer-in-side-window will not
signal an error in that case, but will return nil. If a specified
value just forbids the creation of an additional side window, the most
suitable window on that side is reused and may have its
window-slot parameter changed accordingly.
This option specifies whether top/bottom side windows should appear in
reverse order. When this is nil, side windows on the top and
bottom of a frame are always drawn from left to right with increasing
slot values. When this is t, the drawing order is reversed and
side windows on the top and bottom of a frame are drawn from right to
left with increasing slot values.
When this is bidi, the drawing order is reversed if and only if
the value of bidi-paragraph-direction (see Bidirectional Display) is right-to-left in the buffer displayed in the window
most recently selected within the main window area of this frame.
Sometimes that window may be hard to find, so heuristics are used to
avoid that the drawing order changes inadvertently when another window
gets selected.
The layout of side windows on the left or right of a frame is not affected by the value of this variable.
When a frame has side windows, the following function returns the main window of that frame.
This function returns the main window of the specified frame. The optional argument frame must be a live frame and defaults to the selected one.
If frame has no side windows, it returns frame’s root
window. Otherwise, it returns either an internal non-side window such
that all other non-side windows on frame descend from it, or the
single live non-side window of frame. Note that the main window
of a frame cannot be deleted via delete-window.
The following command is handy to toggle the appearance of all side windows on a specified frame.
This command toggles side windows on the specified frame. The optional argument frame must be a live frame and defaults to the selected one.
If frame has at least one side window, this command saves the
state of frame’s root window in the frame’s
window-state frame parameter and deletes all side windows on
frame afterwards.
If frame has no side windows, but does have a window-state
parameter, this command uses that parameter’s value to restore the side
windows on frame leaving frame’s main window alone.
An error is signaled if frame has no side windows and no saved state is found for it.
Side windows can be used to create more complex frame layouts like those provided by integrated development environments (IDEs). In such layouts, the area of the main window is where the normal editing activities take place. Side windows are not conceived for editing in the usual sense. Rather, they are supposed to display information complementary to the current editing activity, like lists of files, tags or buffers, help information, search or grep results or shell output.
The layout of such a frame might appear as follows:
___________________________________
| *Buffer List* |
|___________________________________|
| | | |
| * | | * |
| d | | T |
| i | | a |
| r | Main Window Area | g |
| e | | s |
| d | | * |
| * | | |
|_____|_______________________|_____|
| *help*/*grep*/ | *shell*/ |
| *Completions* | *compilation* |
|_________________|_________________|
| Echo Area |
|___________________________________|
The following example illustrates how window parameters (see Window Parameters) can be used with display-buffer-in-side-window
(see Displaying Buffers in Side Windows) to set up code for
producing the frame layout sketched above.
(defvar parameters
'(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t))))
(setq fit-window-to-buffer-horizontally t)
(setq window-resize-pixelwise t)
(setq
display-buffer-alist
`(("\\*Buffer List\\*" display-buffer-in-side-window
(side . top) (slot . 0) (window-height . fit-window-to-buffer)
(preserve-size . (nil . t)) ,parameters)
("\\*Tags List\\*" display-buffer-in-side-window
(side . right) (slot . 0) (window-width . fit-window-to-buffer)
(preserve-size . (t . nil)) ,parameters)
("\\*\\(?:help\\|grep\\|Completions\\)\\*"
display-buffer-in-side-window
(side . bottom) (slot . -1) (preserve-size . (nil . t))
,parameters)
("\\*\\(?:shell\\|compilation\\)\\*" display-buffer-in-side-window
(side . bottom) (slot . 1) (preserve-size . (nil . t))
,parameters)))
This specifies display-buffer-alist entries (see Choosing a Window for Displaying a Buffer) for buffers with fixed names. In particular, it asks for
showing *Buffer List* with adjustable height at the top of the
frame and *Tags List* with adjustable width on the frame’s right.
It also asks for having the *help*, *grep* and
*Completions* buffers share a window on the bottom left side of
the frame and the *shell* and *compilation* buffers appear
in a window on the bottom right side of the frame.
Note that the option fit-window-to-buffer-horizontally must
have a non-nil value in order to allow horizontal adjustment of
windows. Entries are also added that ask for preserving the height of
side windows at the top and bottom of the frame and the width of side
windows at the left or right of the frame. To assure that side windows
retain their respective sizes when maximizing the frame, the variable
window-resize-pixelwise is set to a non-nil value.
See Resizing Windows.
The last form also makes sure that none of the created side windows
are accessible via C-x o by installing the no-other-window
parameter for each of these windows. In addition, it makes sure that
side windows are not deleted via C-x 1 by installing the
no-delete-other-windows parameter for each of these windows.
Since dired buffers have no fixed names, we use a special
function dired-default-directory-on-left in order to display a
lean directory buffer on the left side of the frame.
(defun dired-default-directory-on-left ()
"Display `default-directory' in side window on left, hiding details."
(interactive)
(let ((buffer (dired-noselect default-directory)))
(with-current-buffer buffer (dired-hide-details-mode t))
(display-buffer-in-side-window
buffer `((side . left) (slot . 0)
(window-width . fit-window-to-buffer)
(preserve-size . (t . nil)) ,parameters))))
Evaluating the preceding forms and typing, in any order, M-x list-buffers, C-h f, M-x shell, M-x list-tags, and M-x dired-default-directory-on-left should now reproduce the frame layout sketched above.
Atomic windows are rectangular compositions of at least two live windows. They have the following distinctive characteristics:
split-window (see Splitting Windows), when
applied to a constituent of an atomic window, will try to create the new
window outside of the atomic window.
delete-window (see Deleting Windows), when
applied to a constituent of an atomic window, will try to delete the
entire atomic window instead.
delete-other-windows (see Deleting Windows),
when applied to a constituent of an atomic window, will try to make the
atomic window fill its frame or main window (see Side Windows).
This means that the basic groups of functions that alter the window structure treat an atomic window like a live one, thus preserving the internal structure of the atomic window.
Atomic windows are useful to construct and preserve window layouts that are meaningful only when all involved buffers are shown simultaneously in a specific manner, such as when showing differences between file revisions, or the same text in different languages or markups. They can also be used to permanently display information pertinent to a specific window in bars on that window’s sides.
Atomic windows are implemented with the help of the reserved
window-atom window parameter (see Window Parameters) and an
internal window (see Basic Concepts of Emacs Windows) called the root window of the
atomic window. All windows that are part of the same atomic window have
this root window as their common ancestor and are assigned a
non-nil window-atom parameter.
The following function returns the root of the atomic window a specified window is part of:
This functions returns the root of the atomic window window is a
part of. The specified window must be a valid window and defaults
to the selected one. It returns nil if window is not part
of an atomic window.
The most simple approach to make a new atomic window is to take an existing internal window and apply the following function:
This function converts window into an atomic window. The
specified window must be an internal window. All this function
does is to set the window-atom parameter of each descendant of
window to t.
To create a new atomic window from an existing live window or to add a new window to an existing atomic window, the following buffer display action function (see Action Functions for Buffer Display) can be used:
This function tries to display buffer in a new window that will be combined with an existing window to form an atomic window. If the existing window is already part of an atomic window, it adds the new window to that atomic window.
The specified alist is an association list of symbols and values. The following symbols have a special meaning:
windowThe value of such an element specifies an existing window the new window
shall be combined with. If it specifies an internal window, all
children of that window become part of the atomic window too. If no
window is specified, the new window becomes a sibling of the selected
window. The window-atom parameter of the existing window is set
to main provided that window is live and its window-atom
parameter was not already set.
sideThe value of such an element denotes the side of the existing window
where the new window shall be located. Valid values are below,
right, above and left. The default is
below. The window-atom parameter of the new window is set
to this value.
The return value is the new window, nil when creating that window
failed.
Note that the value of the window-atom parameter does not really
matter as long as it is non-nil. The values assigned by
display-buffer-in-atom-window just allow for easy retrieval of
the original and the new window after that function has been applied.
Note also that the window-atom parameter is the only window
parameter assigned by display-buffer-in-atom-window. Further
parameters have to be set by the application explicitly via a
window-parameters entry in alist.
Atomic windows automatically cease to exist when one of their
constituents gets deleted. To dissolve an atomic window manually,
reset the window-atom parameter of its constituents—the root
of the atomic window and all its descendants.
The following code snippet, when applied to a single-window frame, first splits the selected window and makes the selected and the new window constituents of an atomic window with their parent as root. It then displays the buffer *Messages* in a new window at the frame’s bottom and makes that new window part of the atomic window just created.
(let ((window (split-window-right))) (window-make-atom (window-parent window)) (display-buffer-in-atom-window (get-buffer-create "*Messages*") `((window . ,(window-parent window)) (window-height . 5))))
At this moment typing C-x 2 in any window of that frame produces a new window at the bottom of the frame. Typing C-x 3 instead will put the new window at the frame’s right. In either case, typing now C-x 1 in any window of the atomic window will remove the new window only. Typing C-x 0 in any window of the atomic window will make that new window fill the frame.
Each window has its own value of point (see Point), independent of the value of point in other windows displaying the same buffer. This makes it useful to have multiple windows showing one buffer.
Emacs displays the cursor, by default as a rectangular block, in each window at the position of that window’s point. When the user switches to another buffer in a window, Emacs moves that window’s cursor to where point is in that buffer. If the exact position of point is hidden behind some display element, such as a display string or an image, Emacs displays the cursor immediately before or after that display element.
This function returns the current position of point in window. For a nonselected window, this is the value point would have (in that window’s buffer) if that window were selected. The default for window is the selected window.
When window is the selected window, the value returned is the
value of point in that window’s buffer. Strictly speaking, it would be
more correct to return the top-level value of point, outside of any
save-excursion forms. But that value is hard to find.
This function positions point in window at position position in window’s buffer. It returns position.
If window is selected, this simply does goto-char in
window’s buffer.
This variable specifies the marker insertion type (see Marker Insertion Types) of window-point. The default is nil,
so window-point will stay behind text inserted there.
This function sets the cursor shape for window. This setting
takes precedence over the cursor-type variable, and type
has the same format as the value of that variable. See Cursor Parameters. If window is nil, it means to set the cursor
type for the selected window.
The initial value for new windows is t, which says to respect the
buffer-local value of cursor-type. The value set by this
function persists across buffers shown in window, so
set-window-buffer does not reset it. See Buffers and Windows.
This function returns the cursor type of window, defaulting to the selected window.
Each window maintains a marker used to keep track of a buffer position that specifies where in the buffer display should start. This position is called the display-start position of the window (or just the start). The character after this position is the one that appears at the upper left corner of the window. It is usually, but not inevitably, at the beginning of a text line.
After switching windows or buffers, and in some other cases, if the window start is in the middle of a line, Emacs adjusts the window start to the start of a line. This prevents certain operations from leaving the window start at a meaningless point within a line. This feature may interfere with testing some Lisp code by executing it using the commands of Lisp mode, because they trigger this readjustment. To test such code, put it into a command and bind the command to a key.
This function returns the display-start position of window
window. If window is nil, the selected window is
used.
When you create a window, or display a different buffer in it, the
display-start position is set to a display-start position recently used
for the same buffer, or to point-min if the buffer doesn’t have
any.
Redisplay updates the window-start position (if you have not specified it explicitly since the previous redisplay)—to make sure point appears on the screen. Nothing except redisplay automatically changes the window-start position; if you move point, do not expect the window-start position to change in response until after the next redisplay.
This function is like window-start, except that when
window is a part of a group of windows (see Window Group),
window-group-start returns the start position of the entire
group. This condition holds when the buffer local variable
window-group-start-function is set to a function. In this
case, window-group-start calls the function with the single
argument window, then returns its result.
This function returns the position where display of its buffer ends in window. The default for window is the selected window.
Simply changing the buffer text or moving point does not update the
value that window-end returns. The value is updated only when
Emacs redisplays and redisplay completes without being preempted.
If the last redisplay of window was preempted, and did not finish,
Emacs does not know the position of the end of display in that window.
In that case, this function returns nil.
If update is non-nil, window-end always returns an
up-to-date value for where display ends, based on the current
window-start value. If a previously saved value of that position
is still valid, window-end returns that value; otherwise it
computes the correct value by scanning the buffer text.
Even if update is non-nil, window-end does not
attempt to scroll the display if point has moved off the screen, the
way real redisplay would do. It does not alter the
window-start value. In effect, it reports where the displayed
text will end if scrolling is not required. Note that the position it
returns might be only partially visible.
This function is like window-end, except that when window
is a part of a group of windows (see Window Group),
window-group-end returns the end position of the entire group.
This condition holds when the buffer local variable
window-group-end-function is set to a function. In this case,
window-group-end calls the function with the two arguments
window and update, then returns its result. The argument
update has the same meaning as in window-end.
This function sets the display-start position of window to position in window’s buffer. It returns position.
The display routines insist that the position of point be visible when a
buffer is displayed. Normally, they select the display-start position
according to their internal logic (and scroll the window if necessary)
to make point visible. However, if you specify the start position
with this function using nil for noforce, it means you
want display to start at position even if that would put the
location of point off the screen. If this does place point off
screen, the display routines attempt to move point to the left margin
on the middle line in the window.
For example, if point is 1 and you set the start of the window to 37, the start of the next line, point will be above the top of the window. The display routines will automatically move point if it is still 1 when redisplay occurs. Here is an example:
;; Here is what ‘foo’ looks like before executing
;; the set-window-start expression.
---------- Buffer: foo ---------- ∗This is the contents of buffer foo. 2 3 4 5 6 ---------- Buffer: foo ----------
(set-window-start (selected-window) (save-excursion (goto-char 1) (forward-line 1) (point))) ⇒ 37
;; Here is what ‘foo’ looks like after executing
;; the set-window-start expression.
---------- Buffer: foo ----------
2
3
∗4
5
6
---------- Buffer: foo ----------
If the attempt to make point visible (i.e., in a fully-visible screen line) fails, the display routines will disregard the requested window-start position and compute a new one anyway. Thus, for reliable results Lisp programs that call this function should always move point to be inside the window whose display starts at position.
If noforce is non-nil, and position would place point
off screen at the next redisplay, then redisplay computes a new window-start
position that works well with point, and thus position is not used.
This function is like set-window-start, except that when
window is a part of a group of windows (see Window Group),
set-window-group-start sets the start position of the entire
group. This condition holds when the buffer local variable
set-window-group-start-function is set to a function. In this
case, set-window-group-start calls the function with the three
arguments window, position, and noforce, then
returns its result. The arguments position and noforce in
this function have the same meaning as in set-window-start.
This function returns non-nil if position is within the
range of text currently visible on the screen in window. It
returns nil if position is scrolled vertically out of
view. Locations that are partially obscured are not considered
visible unless partially is non-nil. The argument
position defaults to the current position of point in
window; window defaults to the selected window. If
position is t, that means to check either the first
visible position of the last screen line in window, or the
end-of-buffer position, whichever comes first.
This function considers only vertical scrolling. If position is
out of view only because window has been scrolled horizontally,
pos-visible-in-window-p returns non-nil anyway.
See Horizontal Scrolling.
If position is visible, pos-visible-in-window-p returns
t if partially is nil; if partially is
non-nil, and the character following position is fully
visible, it returns a list of the form (x y), where
x and y are the pixel coordinates relative to the top left
corner of the window; otherwise it returns an extended list of the form
(x y rtop rbot rowh vpos),
where rtop and rbot specify the number of off-window pixels
at the top and bottom of the row at position, rowh specifies
the visible height of that row, and vpos specifies the vertical
position (zero-based row number) of that row.
Here is an example:
;; If point is off the screen now, recenter it now.
(or (pos-visible-in-window-p
(point) (selected-window))
(recenter 0))
This function is like pos-visible-in-window-p, except that when
window is a part of a group of windows (see Window Group),
pos-visible-in-window-group-p tests the visibility of pos
in the entire group, not just in the single window. This
condition holds when the buffer local variable
pos-visible-in-window-group-p-function is set to a function.
In this case pos-visible-in-window-group-p calls the function
with the three arguments position, window, and
partially, then returns its result. The arguments
position and partially have the same meaning as in
pos-visible-in-window-p.
This function returns the height of text line line in
window. If line is one of header-line or
mode-line, window-line-height returns information about
the corresponding line of the window. Otherwise, line is a text
line number starting from 0. A negative number counts from the end of
the window. The default for line is the current line in
window; the default for window is the selected window.
If the display is not up to date, window-line-height returns
nil. In that case, pos-visible-in-window-p may be used
to obtain related information.
If there is no line corresponding to the specified line,
window-line-height returns nil. Otherwise, it returns
a list (height vpos ypos offbot),
where height is the height in pixels of the visible part of the
line, vpos and ypos are the vertical position in lines and
pixels of the line relative to the top of the first text line, and
offbot is the number of off-window pixels at the bottom of the
text line. If there are off-window pixels at the top of the (first)
text line, ypos is negative.
Textual scrolling means moving the text up or down through a
window. It works by changing the window’s display-start location. It
may also change the value of window-point to keep point on the
screen (see Windows and Point).
The basic textual scrolling functions are scroll-up (which
scrolls forward) and scroll-down (which scrolls backward). In
these function names, “up” and “down” refer to the direction of
motion of the buffer text relative to the window. Imagine that the
text is written on a long roll of paper and that the scrolling
commands move the paper up and down. Thus, if you are looking at the
middle of a buffer and repeatedly call scroll-down, you will
eventually see the beginning of the buffer.
Unfortunately, this sometimes causes confusion, because some people tend to think in terms of the opposite convention: they imagine the window moving over text that remains in place, so that “down” commands take you to the end of the buffer. This convention is consistent with fact that such a command is bound to a key named PageDown on modern keyboards.
Textual scrolling functions (aside from scroll-other-window)
have unpredictable results if the current buffer is not the one
displayed in the selected window. See The Current Buffer.
If the window contains a row taller than the height of the window
(for example in the presence of a large image), the scroll functions
will adjust the window’s vertical scroll position to scroll the
partially visible row. Lisp callers can disable this feature by
binding the variable auto-window-vscroll to nil
(see Vertical Fractional Scrolling).
This function scrolls forward by count lines in the selected window.
If count is negative, it scrolls backward instead. If
count is nil (or omitted), the distance scrolled is
next-screen-context-lines lines less than the height of the
window’s body.
If the selected window cannot be scrolled any further, this function
signals an error. Otherwise, it returns nil.
This function scrolls backward by count lines in the selected window.
If count is negative, it scrolls forward instead. In other
respects, it behaves the same way as scroll-up does.
This behaves like scroll-up, except that if the selected window
cannot be scrolled any further and the value of the variable
scroll-error-top-bottom is t, it tries to move to the
end of the buffer instead. If point is already there, it signals an
error.
This behaves like scroll-down, except that if the selected
window cannot be scrolled any further and the value of the variable
scroll-error-top-bottom is t, it tries to move to the
beginning of the buffer instead. If point is already there, it
signals an error.
This function scrolls the text in another window upward count
lines. Negative values of count, or nil, are handled
as in scroll-up.
You can specify which buffer to scroll by setting the variable
other-window-scroll-buffer to a buffer. If that buffer isn’t
already displayed, scroll-other-window displays it in some
window.
When the selected window is the minibuffer, the next window is normally
the leftmost one immediately above it. You can specify a different
window to scroll, when the minibuffer is selected, by setting the variable
minibuffer-scroll-window. This variable has no effect when any
other window is selected. When it is non-nil and the
minibuffer is selected, it takes precedence over
other-window-scroll-buffer. See Definition of minibuffer-scroll-window.
This function scrolls the text in another window downward count
lines. Negative values of count, or nil, are handled as
in scroll-down. In other respects, it behaves the same way as
scroll-other-window does.
If this variable is non-nil, it tells scroll-other-window
which buffer’s window to scroll.
This option specifies the size of the scroll margin—a minimum number of lines between point and the top or bottom of a window. Whenever point gets within this many lines of the top or bottom of the window, redisplay scrolls the text automatically (if possible) to move point out of the margin, closer to the center of the window.
This variable limits the effective value of scroll-margin to a
fraction of the current window line height. For example, if the
current window has 20 lines and maximum-scroll-margin is 0.1,
then the scroll margins will never be larger than 2 lines, no matter
how big scroll-margin is.
maximum-scroll-margin itself has a maximum value of 0.5, which
allows setting margins large to keep the cursor at the middle line of
the window (or two middle lines if the window has an even number of
lines). If it’s set to a larger value (or any value other than a
float between 0.0 and 0.5) then the default value of 0.25 will be used
instead.
This variable controls how scrolling is done automatically when point
moves off the screen (or into the scroll margin). If the value is a
positive integer n, then redisplay scrolls the text up to
n lines in either direction, if that will bring point back into
proper view. This behavior is called conservative scrolling.
Otherwise, scrolling happens in the usual way, under the control of
other variables such as scroll-up-aggressively and
scroll-down-aggressively.
The default value is zero, which means that conservative scrolling never happens.
The value of this variable should be either nil or a fraction
f between 0 and 1. If it is a fraction, that specifies where on
the screen to put point when scrolling down. More precisely, when a
window scrolls down because point is above the window start, the new
start position is chosen to put point f part of the window
height from the top. The larger f, the more aggressive the
scrolling.
A value of nil is equivalent to .5, since its effect is to center
point. This variable automatically becomes buffer-local when set in any
fashion.
Likewise, for scrolling up. The value, f, specifies how far
point should be placed from the bottom of the window; thus, as with
scroll-down-aggressively, a larger value scrolls more
aggressively.
This variable is an older variant of scroll-conservatively.
The difference is that if its value is n, that permits scrolling
only by precisely n lines, not a smaller number. This feature
does not work with scroll-margin. The default value is zero.
If this option is t, whenever a scrolling command moves point
off-window, Emacs tries to adjust point to keep the cursor at its old
vertical position in the window, rather than the window edge.
If the value is non-nil and not t, Emacs adjusts point
to keep the cursor at the same vertical position, even if the
scrolling command didn’t move point off-window.
This option affects all scroll commands that have a non-nil
scroll-command symbol property.
The value of this variable is the number of lines of continuity to
retain when scrolling by full screens. For example, scroll-up
with an argument of nil scrolls so that this many lines at the
bottom of the window appear instead at the top. The default value is
2.
If this option is nil (the default), scroll-up-command
and scroll-down-command simply signal an error when no more
scrolling is possible.
If the value is t, these commands instead move point to the
beginning or end of the buffer (depending on scrolling direction);
only if point is already on that position do they signal an error.
This function scrolls the text in the selected window so that point is displayed at a specified vertical position within the window. It does not move point with respect to the text.
If count is a non-negative number, that puts the line containing point count lines down from the top of the window. If count is a negative number, then it counts upward from the bottom of the window, so that −1 stands for the last usable line in the window.
If count is nil (or a non-nil list),
recenter puts the line containing point in the middle of the
window. If count is nil and redisplay is
non-nil, this function may redraw the frame, according to the
value of recenter-redisplay. Thus, omitting the second
argument can be used to countermand the effect of
recenter-redisplay being non-nil. Interactive calls
pass non-nil for redisplay.
When recenter is called interactively, count is the raw
prefix argument. Thus, typing C-u as the prefix sets the
count to a non-nil list, while typing C-u 4 sets
count to 4, which positions the current line four lines from the
top.
With an argument of zero, recenter positions the current line at
the top of the window. The command recenter-top-bottom offers
a more convenient way to achieve this.
This function is like recenter, except that when the selected
window is part of a group of windows (see Window Group),
recenter-window-group scrolls the entire group. This condition
holds when the buffer local variable
recenter-window-group-function is set to a function. In this
case, recenter-window-group calls the function with the
argument count, then returns its result. The argument
count has the same meaning as in recenter, but with
respect to the entire window group.
If this variable is non-nil, calling recenter with a
nil count argument and non-nil redisplay
argument redraws the frame. The default value is tty, which
means only redraw the frame if it is a tty frame.
This command, which is the default binding for C-l, acts like
recenter, except if called with no argument. In that case,
successive calls place point according to the cycling order defined
by the variable recenter-positions.
This variable controls how recenter-top-bottom behaves when
called with no argument. The default value is (middle top
bottom), which means that successive calls of
recenter-top-bottom with no argument cycle between placing
point at the middle, top, and bottom of the window.
Vertical fractional scrolling means shifting text in a window up or down by a specified multiple or fraction of a line. Emacs uses it, for example, on images and screen lines which are taller than the window. Each window has a vertical scroll position, which is a number, never less than zero. It specifies how far to raise the contents of the window when displaying them. Raising the window contents generally makes all or part of some lines disappear off the top, and all or part of some other lines appear at the bottom. The usual value is zero.
The vertical scroll position is measured in units of the normal line height, which is the height of the default font. Thus, if the value is .5, that means the window contents will be scrolled up half the normal line height. If it is 3.3, that means the window contents are scrolled up somewhat over three times the normal line height.
What fraction of a line the vertical scrolling covers, or how many lines, depends on what the lines contain. A value of .5 could scroll a line whose height is very short off the screen, while a value of 3.3 could scroll just part of the way through a tall line or an image.
This function returns the current vertical scroll position of
window. The default for window is the selected window.
If pixels-p is non-nil, the return value is measured in
pixels, rather than in units of the normal line height.
(window-vscroll)
⇒ 0
This function sets window’s vertical scroll position to
lines. If window is nil, the selected window is
used. The argument lines should be zero or positive; if not, it
is taken as zero.
The actual vertical scroll position must always correspond to an integral number of pixels, so the value you specify is rounded accordingly.
The return value is the result of this rounding.
(set-window-vscroll (selected-window) 1.2)
⇒ 1.13
If pixels-p is non-nil, lines specifies a number of
pixels. In this case, the return value is lines.
Normally, the vscroll does not take effect on windows that aren’t the
minibuffer-scroll-window or the selected window when the
mini-window is resized (see Minibuffer 窗口). This “frozen”
behavior is disabled when the preserve-vscroll-p parameter is
non-nil, which means to set the vscroll as usual.
If this variable is non-nil, the line-move,
scroll-up, and scroll-down functions will automatically
modify the vertical scroll position to scroll through display rows
that are taller than the height of the window, for example in the
presence of large images.
Horizontal scrolling means shifting the image in the window left or right by a specified multiple of the normal character width. Each window has a horizontal scroll position, which is a number, never less than zero. It specifies how far to shift the contents left. Shifting the window contents left generally makes all or part of some characters disappear off the left, and all or part of some other characters appear at the right. The usual value is zero.
The horizontal scroll position is measured in units of the normal character width, which is the width of space in the default font. Thus, if the value is 5, that means the window contents are scrolled left by 5 times the normal character width. How many characters actually disappear off to the left depends on their width, and could vary from line to line.
Because we read from side to side in the inner loop, and from top to bottom in the outer loop, the effect of horizontal scrolling is not like that of textual or vertical scrolling. Textual scrolling involves selection of a portion of text to display, and vertical scrolling moves the window contents contiguously; but horizontal scrolling causes part of each line to go off screen.
Usually, no horizontal scrolling is in effect; then the leftmost column is at the left edge of the window. In this state, scrolling to the right is meaningless, since there is no data to the left of the edge to be revealed by it; so this is not allowed. Scrolling to the left is allowed; it scrolls the first columns of text off the edge of the window and can reveal additional columns on the right that were truncated before. Once a window has a nonzero amount of leftward horizontal scrolling, you can scroll it back to the right, but only so far as to reduce the net horizontal scroll to zero. There is no limit to how far left you can scroll, but eventually all the text will disappear off the left edge.
If auto-hscroll-mode is set, redisplay automatically alters
the horizontal scrolling of a window as necessary to ensure that point
is always visible. However, you can still set the horizontal
scrolling value explicitly. The value you specify serves as a lower
bound for automatic scrolling, i.e., automatic scrolling will not
scroll a window to a column less than the specified one.
The default value of auto-hscroll-mode is t; setting
it to current-line activates a variant of automatic horizontal
scrolling whereby only the line showing the cursor is horizontally
scrolled to make point visible, the rest of the window is left either
unscrolled, or at the minimum scroll amount set by scroll-left
and scroll-right, see below.
This function scrolls the selected window count columns to the left (or to the right if count is negative). The default for count is the window width, minus 2.
The return value is the total amount of leftward horizontal scrolling in
effect after the change—just like the value returned by
window-hscroll (below).
Note that text in paragraphs whose base direction is right-to-left
(see Bidirectional Display) moves in the opposite direction: e.g.,
it moves to the right when scroll-left is invoked with a
positive value of count.
Once you scroll a window as far right as it can go, back to its normal position where the total leftward scrolling is zero, attempts to scroll any farther right have no effect.
If set-minimum is non-nil, the new scroll amount becomes
the lower bound for automatic scrolling; that is, automatic scrolling
will not scroll a window to a column less than the value returned by
this function. Interactive calls pass non-nil for
set-minimum.
This function scrolls the selected window count columns to the
right (or to the left if count is negative). The default
for count is the window width, minus 2. Aside from the direction
of scrolling, this works just like scroll-left.
This function returns the total leftward horizontal scrolling of window—the number of columns by which the text in window is scrolled left past the left margin. (In right-to-left paragraphs, the value is the total amount of the rightward scrolling instead.) The default for window is the selected window.
The return value is never negative. It is zero when no horizontal scrolling has been done in window (which is usually the case).
(window-hscroll)
⇒ 0
(scroll-left 5)
⇒ 5
(window-hscroll)
⇒ 5
This function sets horizontal scrolling of window. The value of columns specifies the amount of scrolling, in terms of columns from the left margin (right margin in right-to-left paragraphs). The argument columns should be zero or positive; if not, it is taken as zero. Fractional values of columns are not supported at present.
Note that set-window-hscroll may appear not to work if you test
it by evaluating a call with M-: in a simple way. What happens
is that the function sets the horizontal scroll value and returns, but
then redisplay adjusts the horizontal scrolling to make point visible,
and this overrides what the function did. You can observe the
function’s effect if you call it while point is sufficiently far from
the left margin that it will remain visible.
The value returned is columns.
(set-window-hscroll (selected-window) 10)
⇒ 10
Here is how you can determine whether a given position position is off the screen due to horizontal scrolling:
(defun hscroll-on-screen (window position)
(save-excursion
(goto-char position)
(and
(>= (- (current-column) (window-hscroll window)) 0)
(< (- (current-column) (window-hscroll window))
(window-width window)))))
This section describes functions that report positions of and within a window. Most of these functions report positions relative to an origin at the native position of the window’s frame (see Frame Geometry). Some functions report positions relative to the origin of the display of the window’s frame. In any case, the origin has the coordinates (0, 0) and X and Y coordinates increase rightward and downward respectively.
For the following functions, X and Y coordinates are reported in integer character units, i.e., numbers of lines and columns respectively. On a graphical display, each “line” and “column” corresponds to the height and width of the default character specified by the frame’s default font (see Frame Font).
This function returns a list of the edge coordinates of window.
If window is omitted or nil, it defaults to the selected
window.
The return value has the form (left top right
bottom). These list elements are, respectively, the X
coordinate of the leftmost column occupied by the window, the Y
coordinate of the topmost row, the X coordinate one column to the
right of the rightmost column, and the Y coordinate one row down from
the bottommost row.
Note that these are the actual outer edges of the window, including any of its decorations. On a text terminal, if the window has a neighbor on its right, its right edge includes the separator line between the window and its neighbor.
If the optional argument body is nil, this means to
return the edges corresponding to the total size of window.
body non-nil means to return the edges of window’s
body. If body is non-nil, window must specify a
live window.
If the optional argument absolute is nil, this means to
return edges relative to the native position of window’s frame.
absolute non-nil means to return coordinates relative to
the origin (0, 0) of window’s display. On non-graphical systems
this argument has no effect.
If the optional argument pixelwise is nil, this means to
return the coordinates in terms of the default character width and
height of window’s frame (see Frame Font), rounded if
necessary. pixelwise non-nil means to return the
coordinates in pixels. Note that the pixel specified by right and
bottom is immediately outside of these edges. If absolute
is non-nil, pixelwise is implicitly non-nil too.
This function returns the edges of window’s body (see Window Sizes). Calling (window-body-edges window) is equivalent to
calling (window-edges window t), see above.
The following functions can be used to relate a set of frame-relative coordinates to a window:
This function returns the live window at the coordinates x and y given in default character sizes (see Frame Font) relative to the native position of frame (see Frame Geometry).
If there is no window at that position, the return value is nil.
If frame is omitted or nil, it defaults to the selected
frame.
This function checks whether a window window occupies the frame relative coordinates coordinates, and if so, which part of the window that is. window should be a live window.
coordinates should be a cons cell of the form (x
. y), where x and y are given in default character
sizes (see Frame Font) relative to the native position of
window’s frame (see Frame Geometry).
If there is no window at the specified position, the return value is
nil . Otherwise, the return value is one of the following:
(relx . rely)The coordinates are inside window. The numbers relx and rely are the equivalent window-relative coordinates for the specified position, counting from 0 at the top left corner of the window.
mode-lineThe coordinates are in the mode line of window.
header-lineThe coordinates are in the header line of window.
tab-lineThe coordinates are in the tab line of window.
right-dividerThe coordinates are in the divider separating window from a window on the right.
bottom-dividerThe coordinates are in the divider separating window from a window beneath.
vertical-lineThe coordinates are in the vertical line between window and its neighbor to the right. This value occurs only if the window doesn’t have a scroll bar; positions in a scroll bar are considered outside the window for these purposes.
left-fringeright-fringeThe coordinates are in the left or right fringe of the window.
left-marginright-marginThe coordinates are in the left or right margin of the window.
nilThe coordinates are not in any part of window.
The function coordinates-in-window-p does not require a frame as
argument because it always uses the frame that window is on.
The following functions return window positions in pixels, rather than character units. Though mostly useful on graphical displays, they can also be called on text terminals, where the screen area of each text character is taken to be one pixel.
This function returns a list of pixel coordinates for the edges of
window. Calling (window-pixel-edges window) is equivalent
to calling (window-edges window nil nil t), see above.
This function returns the pixel edges of window’s body. Calling
(window-body-pixel-edges window) is equivalent to calling
(window-edges window t nil t), see above.
The following functions return window positions in pixels, relative to the origin of the display screen rather than that of the frame:
This function returns the pixel coordinates of window relative to
an origin at (0, 0) of the display of window’s frame. Calling
(window-absolute-pixel-edges) is equivalent to calling
(window-edges window nil t t), see above.
This function returns the pixel coordinates of window’s body
relative to an origin at (0, 0) of the display of window’s frame.
Calling (window-absolute-body-pixel-edges window) is equivalent
to calling (window-edges window t t t), see above.
Combined with set-mouse-absolute-pixel-position, this function
can be used to move the mouse pointer to an arbitrary buffer position
visible in some window:
(let ((edges (window-absolute-body-pixel-edges))
(position (pos-visible-in-window-p nil nil t)))
(set-mouse-absolute-pixel-position
(+ (nth 0 edges) (nth 0 position))
(+ (nth 1 edges) (nth 1 position))))
On a graphical terminal this form “warps” the mouse cursor to the upper left corner of the glyph at the selected window’s point. A position calculated this way can be also used to show a tooltip window there.
The following function returns the screen coordinates of a buffer position visible in a window:
If the buffer position position is visible in window window,
this function returns the display coordinates of the upper/left corner
of the glyph at position. The return value is a cons of the X-
and Y-coordinates of that corner, relative to an origin at (0, 0) of
window’s display. It returns nil if position is not
visible in window.
window must be a live window and defaults to the selected
window. position defaults to the value of window-point
of window.
This means that in order to move the mouse pointer to the position of point in the selected window, it’s sufficient to write:
(let ((position (window-absolute-pixel-position))) (set-mouse-absolute-pixel-position (car position) (cdr position)))
The following function returns the largest rectangle that can be inscribed in a window without covering text displayed in that window.
This function calculates the dimensions of the largest empty rectangle that can be inscribed in the specified window’s text area. window must be a live window and defaults to the selected one.
The return value is a triple of the width and the start and end
y-coordinates of the largest rectangle that can be inscribed into the
empty space (space not displaying any text) of the text area of
window. No x-coordinates are returned by this function—any such
rectangle is assumed to end at the right edge of window’s text
area. If no empty space can be found, the return value is nil.
The optional argument count, if non-nil, specifies a
maximum number of rectangles to return. This means that the return
value is a list of triples specifying rectangles with the largest
rectangle first. count can be also a cons cell whose car
specifies the number of rectangles to return and whose CDR, if
non-nil, states that all rectangles returned must be disjoint.
The optional arguments min-width and min-height, if
non-nil, specify the minimum width and height of any rectangle
returned.
The optional argument positions, if non-nil, is a cons cell
whose CAR specifies the uppermost and whose CDR specifies the
lowermost pixel position that must be covered by any rectangle returned.
These positions measure from the start of the text area of window.
The optional argument left, if non-nil, means to return
values suitable for buffers displaying right to left text. In that
case, any rectangle returned is assumed to start at the left edge of
window’s text area.
Note that this function has to retrieve the dimensions of each line of
window’s glyph matrix via window-lines-pixel-dimensions
(see Size of Displayed Text). Hence, this function may also return
nil when the current glyph matrix of window is not
up-to-date.
The following option enables automatically selecting the window under the mouse pointer. This accomplishes a policy similar to that of window managers that give focus to a frame (and thus trigger its subsequent selection) whenever the mouse pointer enters its window-system window (see Input Focus, see 焦点事件).
If this variable is non-nil, Emacs will try to automatically
select the window under the mouse pointer. The following values are
meaningful:
This specifies a delay in seconds after which auto-selection triggers. The window under the mouse pointer is selected after the mouse has remained in it for the entire duration of the delay.
A negative number has a similar effect as a positive number, but selects the window under the mouse pointer only after the mouse pointer has remained in it for the entire duration of the absolute value of that number and in addition has stopped moving.
Any other non-nil value means to select a window instantaneously
as soon as the mouse pointer enters it.
In either case, the mouse pointer must enter the text area of a window in order to trigger its selection. Dragging the scroll bar slider or the mode line of a window conceptually should not cause its auto-selection.
Mouse auto-selection selects the minibuffer window only if it is active, and never deselects the active minibuffer window.
Mouse auto-selection can be used to emulate a focus follows mouse policy
for child frames (see Child Frames) which usually are not tracked by
the window manager. This requires setting the value of
focus-follows-mouse (see Input Focus) to a non-nil
value. If the value of focus-follows-mouse is auto-raise,
entering a child frame with the mouse will raise it automatically above
all other child frames of that frame’s parent frame.
A window configuration records the entire layout of one
frame—all windows, their sizes, their decorations, which buffers they
contain, how those buffers are scrolled, and their value of point, It
also includes the value of minibuffer-scroll-window. As a
special exception, the window configuration does not record the value of
point in the selected window for the current buffer.
You can bring back an entire frame layout by restoring a previously saved window configuration. If you want to record the layout of all frames instead of just one, use a frame configuration instead of a window configuration. See Frame Configurations.
This function returns a new object representing frame’s current
window configuration. The default for frame is the selected
frame. The variable window-persistent-parameters specifies
which window parameters (if any) are saved by this function.
See Window Parameters.
This function restores the configuration of windows and buffers as
specified by configuration, for the frame that
configuration was created for, regardless of whether that frame
is selected or not. The argument configuration must be a value
that was previously returned by current-window-configuration
for that frame. Normally the function also selects the frame which is
recorded in the configuration, but if dont-set-frame is
non-nil, it leaves selected the frame which was already
selected at the start of the function.
Normally the function restores the saved minibuffer (if any), but if
dont-set-miniwindow is non-nil, the minibuffer current
at the start of the function (if any) remains in the mini-window.
If the frame from which configuration was saved is dead, all
this function does is to restore the value of the variable
minibuffer-scroll-window and to adjust the value returned by
minibuffer-selected-window. In this case, the function returns
nil. Otherwise, it returns t.
This function consults the variable
window-restore-killed-buffer-windows (see below) when it tries to
restore a window whose buffer was killed after configuration was
recorded.
Here is a way of using this function to get the same effect as
save-window-excursion:
(let ((config (current-window-configuration)))
(unwind-protect
(progn (split-window-below nil)
...)
(set-window-configuration config)))
This macro records the window configuration of the selected frame, executes forms in sequence, then restores the earlier window configuration. The return value is the value of the final form in forms.
Most Lisp code should not use this macro; save-selected-window
is typically sufficient. In particular, this macro cannot reliably
prevent the code in forms from opening new windows, because new
windows might be opened in other frames (see Choosing a Window for Displaying a Buffer), and
save-window-excursion only saves and restores the window
configuration on the current frame.
This function returns t if object is a window configuration.
This function says whether two window configurations have the same
window layout, but ignores the values of point and the saved scrolling
positions—it can return t even if those aspects differ.
This function returns the frame for which the window configuration config was made.
Other primitives to look inside of window configurations would make sense, but are not implemented because we did not need them. See the file winner.el for some more operations on windows configurations.
The objects returned by current-window-configuration die
together with the Emacs process. In order to store a window
configuration on disk and read it back in another Emacs session, you
can use the functions described next. These functions are also useful
to clone the state of a frame into an arbitrary live window
(set-window-configuration effectively clones the windows of a
frame into the root window of that very frame only).
This function returns the state of window as a Lisp object. The argument window must be a valid window and defaults to the root window of the selected frame.
If the optional argument writable is non-nil, this means to
not use markers for sampling positions like window-point or
window-start. This argument should be non-nil when the
state will be written to disk and read back in another session.
Together, the argument writable and the variable
window-persistent-parameters specify which window parameters are
saved by this function. See Window Parameters.
The value returned by window-state-get can be used in the same
session to make a clone of a window in another window. It can be also
written to disk and read back in another session. In either case, use
the following function to restore the state of the window.
This function puts the window state state into window.
The argument state should be the state of a window returned by
an earlier invocation of window-state-get, see above. The
optional argument window can be either a live window or an
internal window (see Windows and Frames). If window is not
a live window, it is replaced by a new live window created on the same
frame before putting state into it. If window is nil,
it puts the window state into a new window.
This function consults the variable
window-restore-killed-buffer-windows (see below) when it tries to
restore a window whose buffer was killed after state was recorded.
If the optional argument ignore is non-nil, it means to ignore
minimum window sizes and fixed-size restrictions. If ignore
is safe, this means windows can get as small as one line
and/or two columns.
By default, set-window-configuration and window-state-put
may delete a window from the restored configuration when they find out
that its buffer was killed since the corresponding configuration or
state has been recorded. The variable described next can be used to
fine-tune that behavior.
This variable specifies how set-window-configuration and
window-state-put shall handle a window whose buffer has been
killed since the corresponding configuration or state was recorded. Any
such window may be live—in which case it shows some other buffer—or
dead at the time one of these functions is called. Usually,
set-window-configuration leaves the window alone if it is live
while window-state-put deletes it.
The following values can be used to override the default behavior for
dead windows in the case of set-window-configuration and for dead
and live windows in the case of window-state-put.
tThis value means to unconditionally restore the window and show some other buffer in it.
deleteThis means to unconditionally try to delete the window.
dedicatedThis means to try to delete the window if and only if it is dedicated to its buffer.
nilThis is the default, and it means that set-window-configuration
will try to delete the window if and only if it is dedicated to its
buffer, and window-state-put will unconditionally try to delete
it.
This means to restore the window and show some other buffer in it, like
if the value is t, and also add an entry for that window to a
list that will be later passed as the second argument to that function.
If a window cannot be deleted (typically, because it is the last window
on its frame), set-window-configuration and
window-state-put will show another buffer in it.
If the value of this variable is a function, that function should take
three arguments. The first argument specifies the frame whose windows
have been restored. The third argument is either the symbol
configuration if the windows are restored by
set-window-configuration, or the symbol state if the
windows are restored by window-state-put.
The second argument specifies a list of entries for all windows
whose previous buffers have been found dead at the time
set-window-configuration or window-state-put tried to
restore them (minibuffer windows are excluded). This means that the
function may also delete windows which were found live by
set-window-configuration.
Each entry in the list that is passed as the second argument to the
function is itself a list of six values: the window whose buffer was
found dead, the dead buffer or its name, the positions of window-start
(see The Window Start and End Positions) and window-point (see Windows and Point)
of the buffer in that window, the dedicated state of the window as
previously reported by window-dedicated-p and a flag that is
t if the window has been found to be alive by
set-window-configuration and nil otherwise.
The functions window-state-get and window-state-put also
allow exchanging the contents of two live windows. The following
function does precisely that:
This command swaps the states of the two live windows window-1 and window-2. window-1 must specify a live window and defaults to the selected one. window-2 must specify a live window and defaults to the window following window-1 in the cyclic ordering of windows, excluding minibuffer windows and including live windows on all visible frames.
Optional argument size non-nil means to try swapping the
sizes of window-1 and window-2 as well. A value of
height means to swap heights only, a value of width
means to swap widths only, while t means to swap both widths
and heights, if possible. Frames are not resized by this function.
This section describes the window parameters that can be used to associate additional information with windows.
This function returns window’s value for parameter. The
default for window is the selected window. If window has no
setting for parameter, this function returns nil.
This function returns all parameters of window and their values.
The default for window is the selected window. The return value
is either nil, or an association list whose elements have the form
(parameter . value).
This function sets window’s value of parameter to value and returns value. The default for window is the selected window.
By default, the functions that save and restore window configurations
or the states of windows (see Window Configurations) do not care
about window parameters. This means that when you change the value of
a parameter within the body of a save-window-excursion, the
previous value is not restored when that macro exits. It also means
that when you restore via window-state-put a window state saved
earlier by window-state-get, all cloned windows have their
parameters reset to nil. The following variable allows you to
override the standard behavior:
This variable is an alist specifying which parameters get saved by
current-window-configuration and window-state-get, and
subsequently restored by set-window-configuration and
window-state-put. See Window Configurations.
The CAR of each entry of this alist is a symbol specifying the parameter. The CDR should be one of the following:
nilThis value means the parameter is saved neither by
window-state-get nor by current-window-configuration.
tThis value specifies that the parameter is saved by
current-window-configuration and (provided its writable
argument is nil) by window-state-get.
writableThis means that the parameter is saved unconditionally by both
current-window-configuration and window-state-get. This
value should not be used for parameters whose values do not have a read
syntax. Otherwise, invoking window-state-put in another session
may fail with an invalid-read-syntax error.
Some functions (notably delete-window,
delete-other-windows and split-window), may behave
specially when the window specified by their window argument has
a parameter whose name is equal to the function’s name. You can
override such special behavior by binding the following variable to a
non-nil value:
If this variable is non-nil, some standard functions do not
process window parameters. The functions currently affected by this are
split-window, delete-window, delete-other-windows,
and other-window.
An application can bind this variable to a non-nil value around
calls to these functions. If it does so, the application is fully
responsible for correctly assigning the parameters of all involved
windows when exiting that function.
The following parameters are currently used by the window management code:
delete-window ¶This parameter affects the execution of delete-window
(see Deleting Windows).
delete-other-windows ¶This parameter affects the execution of delete-other-windows
(see Deleting Windows).
no-delete-other-windows ¶This parameter marks the window as not deletable by
delete-other-windows (see Deleting Windows).
split-window ¶This parameter affects the execution of split-window
(see Splitting Windows).
other-window ¶This parameter affects the execution of other-window
(see Cyclic Ordering of Windows).
no-other-window ¶This parameter marks the window as not selectable by other-window
(see Cyclic Ordering of Windows).
clone-of ¶This parameter specifies the window that this one has been cloned
from. It is installed by window-state-get (see Window Configurations).
window-preserved-size ¶This parameter specifies a buffer, a direction where nil means
vertical and t horizontal, and a size in pixels. If this window
displays the specified buffer and its size in the indicated direction
equals the size specified by this parameter, then Emacs will try to
preserve the size of this window in the indicated direction. This
parameter is installed and updated by the function
window-preserve-size (see Preserving Window Sizes).
quit-restore ¶This parameter is installed by the buffer display functions
(see Choosing a Window for Displaying a Buffer) and consulted by quit-restore-window
(see Quitting Windows). It is a list of four elements, see the
description of quit-restore-window in Quitting Windows
for details.
window-side ¶window-slotThese parameters are used internally for implementing side windows (see Side Windows).
window-atom ¶This parameter is used internally for implementing atomic windows, see Atomic Windows.
mode-line-format ¶This parameter replaces the value of the buffer-local variable
mode-line-format (see 模式行基础) of this window’s
buffer whenever this window is displayed. The symbol none means
to suppress display of a mode line for this window. Display and
contents of the mode line on other windows showing this buffer are not
affected.
header-line-format ¶This parameter replaces the value of the buffer-local variable
header-line-format (see 模式行基础) of this window’s
buffer whenever this window is displayed. The symbol none means
to suppress display of a header line for this window. Display and
contents of the header line on other windows showing this buffer are not
affected.
tab-line-format ¶This parameter replaces the value of the buffer-local variable
tab-line-format (see 模式行基础) of this window’s
buffer whenever this window is displayed. The symbol none means
to suppress display of a tab line for this window. Display and
contents of the tab line on other windows showing this buffer are not
affected.
min-margins ¶The value of this parameter is a cons cell whose CAR and
CDR, if non-nil, specify the minimum values (in columns)
for the left and right margin of this window (see Displaying in the Margins.
When present, Emacs will use these values instead of the actual margin
widths for determining whether a window can be split or shrunk
horizontally.
Emacs never auto-adjusts the margins of any window after splitting or
resizing it. It is the sole responsibility of any application setting
this parameter to adjust the margins of this window as well as those of
any new window that inherits this window’s margins due to a split.
Both window-configuration-change-hook and
window-size-change-functions (see Hooks for Window Scrolling and Changes) should be
employed for this purpose.
This parameter was introduced in Emacs version 25.1 to support applications that use large margins to center buffer text within a window and should be used, with due care, exclusively by those applications. It might be replaced by an improved solution in future versions of Emacs.
This section describes how Lisp programs can take action after a window has been scrolled or other window modifications occurred. We first consider the case where a window shows a different part of its buffer.
This variable holds a list of functions that Emacs should call before redisplaying a window with scrolling. Displaying a different buffer in a window and making a new window also call these functions.
This variable is not a normal hook, because each function is called with two arguments: the window, and its new display-start position. At the time of the call, the display-start position of the argument window is already set to its new value, and the buffer to be displayed in the window is set as the current buffer.
These functions must take care when using window-end
(see The Window Start and End Positions); if you need an up-to-date value, you
must use the update argument to ensure you get it.
Warning: don’t use this feature to alter the way the window is scrolled. It’s not designed for that, and such use probably won’t work.
In addition, you can use jit-lock-register to register a Font
Lock fontification function, which will be called whenever parts of a
buffer are (re)fontified because a window was scrolled or its size
changed. See 字体锁定其他变量.
The remainder of this section covers six hooks that are called
during redisplay provided a significant, non-scrolling change of a
window has been detected. For simplicity, these hooks and the
functions they call will be collectively referred to as window
change functions. As any hook, these hooks can be set either
globally or buffer-locally via the local argument of
add-hook (see 设置钩子) when the hook is installed.
The first of these hooks is run after a window buffer change is detected, which means that a window was created, deleted or assigned another buffer.
This variable specifies functions called during redisplay when window buffers have changed. The value should be a list of functions that take one argument.
Functions specified buffer-locally are called for any window showing the corresponding buffer if that window has been created or assigned that buffer since the last time window change functions were run. In this case the window is passed as argument.
Functions specified by the default value are called for a frame if at least one window on that frame has been added, deleted or assigned another buffer since the last time window change functions were run. In this case the frame is passed as argument.
The second of these hooks is run when a window size change has been detected which means that a window was created, assigned another buffer, or changed its total size or that of its text area.
This variable specifies functions called during redisplay when a window size change occurred. The value should be a list of functions that take one argument.
Functions specified buffer-locally are called for any window showing the corresponding buffer if that window has been added or assigned another buffer or changed its total or body size since the last time window change functions were run. In this case the window is passed as argument.
Functions specified by the default value are called for a frame if at least one window on that frame has been added or assigned another buffer or changed its total or body size since the last time window change functions were run. In this case the frame is passed as argument.
The third of these hooks is run when a window selection change has selected another window since the last redisplay.
This variable specifies functions called during redisplay when the selected window or a frame’s selected window has changed. The value should be a list of functions that take one argument.
Functions specified buffer-locally are called for any window showing the corresponding buffer if that window has been selected or deselected (among all windows or among all windows on its frame) since the last time window change functions were run. In this case the window is passed as argument.
Functions specified by the default value are called for a frame if that frame has been selected or deselected or the frame’s selected window has changed since the last time window change functions were run. In this case the frame is passed as argument.
The fourth of these hooks is run when a window state change has been detected, which means that at least one of the three preceding window changes has occurred.
This variable specifies functions called during redisplay when a window buffer or size change occurred or the selected window or a frame’s selected window has changed. The value should be a list of functions that take one argument.
Functions specified buffer-locally are called for any window showing the corresponding buffer if that window has been added or assigned another buffer, changed its total or body size or has been selected or deselected (among all windows or among all windows on its frame) since the last time window change functions were run. In this case the window is passed as argument.
Functions specified by the default value are called for a frame if at least one window on that frame has been added, deleted or assigned another buffer, changed its total or body size or that frame has been selected or deselected or the frame’s selected window has changed since the last time window change functions were run. In this case the frame is passed as argument.
Functions specified by the default value are also run for a frame when that frame’s window state change flag (see below) has been set since last redisplay.
The fifth of these hooks is run when a window configuration change has been detected which means that either the buffer or the size of a window changed. It differs from the four preceding hooks in the way it is run.
This variable specifies functions called during redisplay when either the buffer or the size of a window has changed. The value should be a list of functions that take no argument.
Functions specified buffer-locally are called for any window showing the corresponding buffer if at least one window on that frame has been added, deleted or assigned another buffer or changed its total or body size since the last time window change functions were run. Each call is performed with the window showing the buffer temporarily selected and its buffer current.
Functions specified by the default value are called for each frame if at least one window on that frame has been added, deleted or assigned another buffer or changed its total or body size since the last time window change functions were run. Each call is performed with the frame temporarily selected and the selected window’s buffer current.
Finally, Emacs runs a normal hook that generalizes the behavior of
window-state-change-functions.
The default value of this variable specifies functions called during redisplay when a window state change has been detected or the window state change flag has been set on at least one frame. The value should be a list of functions that take no argument.
Applications should put a function on this hook only if they want to
react to changes that happened on (or have been signaled for) two or
more frames since last redisplay. In every other case, putting the
function on window-state-change-functions should be preferred.
Window change functions are called during redisplay for each frame as
follows: First, any buffer-local window buffer change function, window
size change function, selected window change and window state change
functions are called in this order. Next, the default values for
these functions are called in the same order. Then any buffer-local
window configuration change functions are called followed by functions
specified by the default value of those functions. Finally, functions
on window-state-change-hook are run.
Window change functions are run for a specific frame only if a corresponding change was registered for that frame earlier. Such changes include the creation or deletion of a window or the assignment of another buffer or size to a window. Note that even when such a change has been registered, this does not mean that any of the hooks described above is run. If, for example, a change was registered within the scope of a window excursion (see Window Configurations), this will trigger a call of window change functions only if that excursion still persists at the time change functions are run. If it is exited earlier, hooks will be run only if registered by a change outside the scope of that excursion.
The window state change flag of a frame, if set, will cause
the default values of window-state-change-functions (for that
frame) and window-state-change-hook to be run during next
redisplay regardless of whether a window state change actually
occurred for that frame or not. After running any functions on these
hooks, the flag is reset for each frame. Applications can set that
flag and inspect its value using the following functions.
This function sets frame’s window state change flag if arg
is non-nil and resets it otherwise. frame must be a live
frame and defaults to the selected one.
This functions returns t if frame’s window state change
flag is set and nil otherwise. frame must be a live
frame and defaults to the selected one.
While window change functions are run, the functions described next can be called to get more insight into what has changed for a specific window or frame since the last redisplay. All these functions take a live window as single, optional argument, defaulting to the selected window.
This function returns the buffer shown in window at the last
time window change functions were run for window’s frame. If it
returns nil, window has been created after that. If it
returns t, window was not shown at that time but has been
restored from a previously saved window configuration afterwards.
Otherwise, the return value is the buffer shown by window at
that time.
This function returns the total pixel width of window the last time window change functions found window live on its frame. It is zero if window was created after that.
This function returns the total pixel height of window the last time window change functions found window live on its frame. It is zero if window was created after that.
This function returns the pixel width of window’s text area the last time window change functions found window live on its frame. It is zero if window was created after that.
This function returns the pixel height of window’s text area the last time window change functions found window live on its frame. It is zero if window was created after that.
In order to find out which window or frame was selected the last time window change functions were run, the following functions can be used:
This function returns the selected window of frame at the last
time window change functions were run. If omitted or nil
frame defaults to the selected frame.
This function returns the selected window at the last time window change functions were run.
This function returns the selected frame at the last time window change functions were run.
Note that window change functions provide no information about which windows have been deleted since the last time they were run. If necessary, applications should remember any window showing a specific buffer in a local variable of that buffer and update it in a function run by the default values of any of the hooks that are run when a window buffer change was detected.
The following caveats should be considered when adding a function to window change functions:
window-state-change-hook.
save-window-excursion, with-selected-window
or with-current-buffer can be used when running window change
functions.
window-configuration-change-hook it does not
save or restore the selected window or frame or the current buffer
either.
A frame is a screen object that contains one or more Emacs windows (see Windows). It is the kind of object called a “window” in the terminology of graphical environments; but we can’t call it a “window” here, because Emacs uses that word in a different way. In Emacs Lisp, a frame object is a Lisp object that represents a frame on the screen. See 框架类型.
A frame initially contains a single main window and/or a minibuffer window; you can subdivide the main window vertically or horizontally into smaller windows. See Splitting Windows.
A terminal is a display device capable of displaying one or more Emacs frames. In Emacs Lisp, a terminal object is a Lisp object that represents a terminal. See 终端类型.
There are two classes of terminals: text terminals and
graphical terminals. Text terminals are non-graphics-capable
displays, including xterm and other terminal emulators. On
a text terminal, each Emacs frame occupies the terminal’s entire
screen; although you can create additional frames and switch between
them, the terminal only shows one frame at a time. Graphical
terminals, on the other hand, are managed by graphical display systems
such as the X Window System, which allow Emacs to show multiple frames
simultaneously on the same display.
On GNU and Unix systems, you can create additional frames on any available terminal, within a single Emacs session, regardless of whether Emacs was started on a text or graphical terminal. Emacs can display on both graphical and text terminals simultaneously. This comes in handy, for instance, when you connect to the same session from several remote locations. See Multiple Terminals.
This predicate returns a non-nil value if object is a
frame, and nil otherwise. For a frame, the value indicates which
kind of display the frame uses:
tThe frame is displayed on a text terminal.
xThe frame is displayed on an X graphical terminal.
w32The frame is displayed on a MS-Windows graphical terminal.
nsThe frame is displayed on a GNUstep or Macintosh Cocoa graphical terminal.
pcThe frame is displayed on an MS-DOS terminal.
haikuThe frame is displayed using the Haiku Application Kit.
pgtkThe frame is displayed using pure GTK facilities.
androidThe frame is displayed on an Android device.
This function returns the terminal object that displays frame.
If frame is nil or unspecified, it defaults to the
selected frame.
This predicate returns a non-nil value if object is a
terminal that is live (i.e., not deleted), and nil otherwise.
For live terminals, the return value indicates what kind of frames are
displayed on that terminal; the list of possible values is the same as
for framep above.
On a graphical terminal we distinguish two types of frames: A normal top-level frame is a frame whose window-system window is a child of the window-system’s root window for that terminal. A child frame is a frame whose window-system window is the child of the window-system window of another Emacs frame. See Child Frames.
To create a new frame, call the function make-frame.
This function creates and returns a new frame, displaying the current buffer.
The parameters argument is an alist that specifies frame
parameters for the new frame. See Frame Parameters. If you specify
the terminal parameter in parameters, the new frame is
created on that terminal. Otherwise, if you specify the
window-system frame parameter in parameters, that
determines whether the frame should be displayed on a text terminal or a
graphical terminal. See Window Systems. If neither is specified,
the new frame is created in the same terminal as the selected frame.
Any parameters not mentioned in parameters default to the values
in the alist default-frame-alist (see Initial Frame Parameters);
parameters not specified there default from the X resources or its
equivalent on your operating system (see X Resources in The GNU Emacs Manual). After the frame is created, this
function applies any parameters specified in
frame-inherited-parameters (see below) it has no assigned yet,
taking the values from the frame that was selected when
make-frame was called.
Note that on multi-monitor displays (see Multiple Terminals), the window manager might position the frame differently than specified by the positional parameters in parameters (see Position Parameters). For example, some window managers have a policy of displaying the frame on the monitor that contains the largest part of the window (a.k.a. the dominating monitor).
This function itself does not make the new frame the selected frame. See Input Focus. The previously selected frame remains selected. On graphical terminals, however, the window system may select the new frame for its own reasons.
A normal hook run by make-frame before it creates the frame.
An abnormal hook run by make-frame after it created the frame.
Each function in after-make-frame-functions receives one
argument, the frame just created.
Note that any functions added to these hooks by your initial file are usually not run for the initial frame, since Emacs reads the initial file only after creating that frame. However, if the initial frame is specified to use a separate minibuffer frame (see Minibuffers and Frames), the functions will be run for both, the minibuffer-less and the minibuffer frame. Alternatively, you can add functions to these hooks in your “early init file” (see The Init File), in which case they will be in effect for the initial frame as well.
This variable specifies the list of frame parameters that a newly
created frame inherits from the currently selected frame. For each
parameter (a symbol) that is an element in this list and has not been
assigned earlier when processing make-frame, the function sets
the value of that parameter in the created frame to its value in the
selected frame.
A normal hook run when the Emacs server starts using a client frame.
When this hook is called, the client frame is the selected one. Note
that, depending on how emacsclient was invoked
(see Invoking emacsclient in The GNU Emacs Manual), this
client frame could be a new frame created for the client, or it could
be an existing frame that the server reused for handling the client
commands. See Emacs Server in The GNU Emacs Manual.
Emacs represents each terminal as a terminal object data type (see 终端类型). On GNU and Unix systems, Emacs can use multiple terminals simultaneously in each session. On other systems, it can only use a single terminal. Each terminal object has the following attributes:
terminal-live-p (i.e., x,
t, w32, ns, pc, haiku, pgtk,
or android). See Frames.
There is no primitive for creating terminal objects. Emacs creates
them as needed, such as when you call make-frame-on-display
(described below).
This function returns the file name of the device used by
terminal. If terminal is omitted or nil, it
defaults to the selected frame’s terminal. terminal can also be
a frame, meaning that frame’s terminal.
This function returns a list of all live terminal objects.
This function returns a terminal whose device name is given by
device. If device is a string, it can be either the file
name of a terminal device, or the name of an X display of the form
‘host:server.screen’. If device is a
frame, this function returns that frame’s terminal; nil means
the selected frame. Finally, if device is a terminal object
that represents a live terminal, that terminal is returned. The
function signals an error if its argument is none of the above.
This function deletes all frames on terminal and frees the
resources used by it. It runs the abnormal hook
delete-terminal-functions, passing terminal as the
argument to each function.
If terminal is omitted or nil, it defaults to the
selected frame’s terminal. terminal can also be a frame,
meaning that frame’s terminal.
Normally, this function signals an error if you attempt to delete the
sole active terminal, but if force is non-nil, you are
allowed to do so. Emacs automatically calls this function when the
last frame on a terminal is deleted (see Deleting Frames).
An abnormal hook run by delete-terminal. Each function
receives one argument, the terminal argument passed to
delete-terminal. Due to technical details, the functions may
be called either just before the terminal is deleted, or just
afterwards.
A few Lisp variables are terminal-local; that is, they have a
separate binding for each terminal. The binding in effect at any time
is the one for the terminal that the currently selected frame belongs
to. These variables include default-minibuffer-frame,
defining-kbd-macro, last-kbd-macro, and
system-key-alist. They are always terminal-local, and can
never be buffer-local (see 缓冲区局部变量).
On GNU and Unix systems, each X display is a separate graphical
terminal. When Emacs is started from within the X window system, it
uses the X display specified by the DISPLAY environment
variable, or by the ‘--display’ option (see Initial Options in The GNU Emacs Manual). Emacs can connect to other X displays
via the command make-frame-on-display. Each X display has its
own selected frame and its own minibuffer windows; however, only one
of those frames is the selected frame at any given moment
(see Input Focus). Emacs can even connect to other text
terminals, by interacting with the emacsclient program.
See Emacs Server in The GNU Emacs Manual.
A single X server can handle more than one display. Each X display has a three-part name, ‘hostname:displaynumber.screennumber’. The first part, hostname, specifies the name of the machine to which the display is physically connected. The second part, displaynumber, is a zero-based number that identifies one or more monitors connected to that machine that share a common keyboard and pointing device (mouse, tablet, etc.). The third part, screennumber, identifies a zero-based screen number (a separate monitor) that is part of a single monitor collection on that X server. When you use two or more screens belonging to one server, Emacs knows by the similarity in their names that they share a single keyboard.
Systems that don’t use the X window system, such as MS-Windows, don’t support the notion of X displays, and have only one display on each host. The display name on these systems doesn’t follow the above 3-part format; for example, the display name on MS-Windows systems is a constant string ‘w32’, and exists for compatibility, so that you could pass it to functions that expect a display name.
This function creates and returns a new frame on display, taking the other frame parameters from the alist parameters. display should be the name of an X display (a string).
Before creating the frame, this function ensures that Emacs is set
up to display graphics. For instance, if Emacs has not processed X
resources (e.g., if it was started on a text terminal), it does so at
this time. In all other respects, this function behaves like
make-frame (see Creating Frames).
This function returns a list that indicates which X displays Emacs has a connection to. The elements of the list are strings, and each one is a display name.
This function opens a connection to the X display display,
without creating a frame on that display. Normally, Emacs Lisp
programs need not call this function, as make-frame-on-display
calls it automatically. The only reason for calling it is to check
whether communication can be established with a given X display.
The optional argument xrm-string, if not nil, is a string
of resource names and values, in the same format used in the
.Xresources file. See X Resources in The
GNU Emacs Manual. These values apply to all Emacs frames created on
this display, overriding the resource values recorded in the X server.
Here’s an example of what this string might look like:
"*BorderWidth: 3\n*InternalBorder: 2\n"
If must-succeed is non-nil, failure to open the connection
terminates Emacs. Otherwise, it is an ordinary Lisp error.
This function closes the connection to display display. Before you can do this, you must first delete all the frames that were open on that display (see Deleting Frames).
On some multi-monitor setups, a single X display outputs to more
than one physical monitor. You can use the functions
display-monitor-attributes-list and frame-monitor-attributes
to obtain information about such setups.
This function returns a list of physical monitor attributes on
display, which can be a display name (a string), a terminal, or
a frame; if omitted or nil, it defaults to the selected frame’s
display. Each element of the list is an association list,
representing the attributes of a physical monitor. The first element
corresponds to the primary monitor. The attribute keys and values
are:
Position of the top-left corner of the monitor’s screen and its size, in pixels, as ‘(x y width height)’. Note that, if the monitor is not the primary monitor, some of the coordinates might be negative.
Position of the top-left corner and size of the work area (usable space) in pixels as ‘(x y width height)’. This may be different from ‘geometry’ in that space occupied by various window manager features (docks, taskbars, etc.) may be excluded from the work area. Whether or not such features actually subtract from the work area depends on the platform and environment. Again, if the monitor is not the primary monitor, some of the coordinates might be negative.
Width and height in millimeters as ‘(width height)’
List of frames that this physical monitor dominates (see below).
Name of the physical monitor as string.
Source of the multi-monitor information as string; on X, it could be ‘XRandR 1.5’, ‘XRandr’, ‘Xinerama’, ‘Gdk’, or ‘fallback’. The last value of ‘source’ means that Emacs was built without GTK and without XRandR or Xinerama extensions, in which case the information about multiple physical monitors will be provided as if they all as a whole formed a single monitor.
x, y, width, and height are integers. ‘name’ and ‘source’ may be absent.
A frame is dominated by a physical monitor when either the largest area of the frame resides in that monitor, or (if the frame does not intersect any physical monitors) that monitor is the closest to the frame. Every (non-tooltip) frame (whether visible or not) in a graphical display is dominated by exactly one physical monitor at a time, though the frame can span multiple (or no) physical monitors.
Here’s an example of the data produced by this function on a 2-monitor display:
(display-monitor-attributes-list) ⇒ (((geometry 0 0 1920 1080) ;; Left-hand, primary monitor (workarea 0 0 1920 1050) ;; A taskbar occupies some of the height (mm-size 677 381) (name . "DISPLAY1") (frames #<frame emacs@host *Messages* 0x11578c0> #<frame emacs@host *scratch* 0x114b838>)) ((geometry 1920 0 1680 1050) ;; Right-hand monitor (workarea 1920 0 1680 1050) ;; Whole screen can be used (mm-size 593 370) (name . "DISPLAY2") (frames)))
This function returns the attributes of the physical monitor dominating (see above) frame, which defaults to the selected frame.
On multi-monitor displays it is possible to use the command
make-frame-on-monitor to make frames on the specified monitor.
This function creates and returns a new frame on monitor located
on display, taking the other frame parameters from the alist
parameters. monitor should be the name of the physical
monitor, the same string as returned by the function
display-monitor-attributes-list in the attribute name.
display should be the name of an X display (a string).
This variable is an abnormal hook run when the monitor configuration
changes, which can happen if a monitor is rotated, moved, added or
removed from a multiple-monitor setup, if the primary monitor changes,
or if the resolution of a monitor changes. It is called with a single
argument consisting of the terminal on which the monitor configuration
changed. Programs should call display-monitor-attributes-list
with the terminal as the argument to retrieve the new monitor
configuration on that terminal.
The geometry of a frame depends on the toolkit that was used to build
this instance of Emacs and the terminal that displays the frame. This
chapter describes these dependencies and some of the functions to deal
with them. Note that the frame argument of all of these functions
has to specify a live frame (see Deleting Frames). If omitted or
nil, it specifies the selected frame (see Input Focus).
A visible frame occupies a rectangular area on its terminal’s display. This area may contain a number of nested rectangles, each serving a different purpose. The drawing below sketches the layout of a frame on a graphical terminal:
<------------ Outer Frame Width ----------->
____________________________________________
^(0) ________ External/Outer Border _______ |
| | |_____________ Title Bar ______________| |
| | (1)_____________ Menu Bar ______________| | ^
| | (2)_____________ Tool Bar ______________| | ^
| | (3)_____________ Tab Bar _______________| | ^
| | | _________ Internal Border ________ | | ^
| | | | ^ | | | |
| | | | | | | | |
Outer | | | Inner | | | Native
Frame | | | Frame | | | Frame
Height | | | Height | | | Height
| | | | | | | | |
| | | |<--+--- Inner Frame Width ------->| | | |
| | | | | | | | |
| | | |___v______________________________| | | |
| | |___________ Internal Border __________| | |
| | (4)__________ Bottom Tool Bar __________| | v
v |___________ External/Outer Border __________|
<-------- Native Frame Width -------->
In practice not all of the areas shown in the drawing will or may be present. The meaning of these areas is described below.
The outer frame is a rectangle comprising all areas shown in the drawing. The edges of that rectangle are called the outer edges of the frame. Together, the outer width and outer height of the frame specify the outer size of that rectangle.
Knowing the outer size of a frame is useful for fitting a frame into the working area of its display (see Multiple Terminals) or for placing two frames adjacent to each other on the screen. Usually, the outer size of a frame is available only after the frame has been mapped (made visible, see Visibility of Frames) at least once. For the initial frame or a frame that has not been created yet, the outer size can be only estimated or must be calculated from the window-system’s or window manager’s defaults. One workaround is to obtain the differences of the outer and native (see below) sizes of a mapped frame and use them for calculating the outer size of the new frame.
The position of the upper left corner of the outer frame (indicated by ‘(0)’ in the drawing above) is the outer position of the frame. The outer position of a graphical frame is also referred to as “the position” of the frame because it usually remains unchanged on its display whenever the frame is resized or its layout is changed.
The outer position is specified by and can be set via the left
and top frame parameters (see Position Parameters). For a
normal, top-level frame these parameters usually represent its absolute
position (see below) with respect to its display’s origin. For a child
frame (see Child Frames) these parameters represent its position
relative to the native position (see below) of its parent frame. For
frames on text terminals the values of these parameters are meaningless
and always zero.
The external border is part of the decorations supplied by the window manager. It is typically used for resizing the frame with the mouse and is therefore not shown on “fullboth” and maximized frames (see Size Parameters). Its width is determined by the window manager and cannot be changed by Emacs’s functions.
External borders don’t exist on text terminal frames. For graphical
frames, their display can be suppressed by setting the
override-redirect or undecorated frame parameter
(see Window Management Parameters).
The outer border is a separate border whose width can be specified
with the border-width frame parameter (see Layout Parameters). In practice, either the external or the outer border of a
frame are displayed but never both at the same time. Usually, the outer
border is shown only for special frames that are not (fully) controlled
by the window manager like tooltip frames (see Tooltips), child
frames (see Child Frames) and undecorated or
override-redirect frames (see Window Management Parameters).
Outer borders are never shown on text terminal frames and on frames
generated by GTK+ routines. On MS-Windows, the outer border is emulated
with the help of a one pixel wide external border. Non-toolkit builds
on X allow changing the color of the outer border by setting the
border-color frame parameter (see Layout Parameters).
The title bar, a.k.a. caption bar, is also part of the
window manager’s decorations and typically displays the title of the
frame (see Frame Titles) as well as buttons for minimizing,
maximizing and deleting the frame. It can be also used for dragging
the frame with the mouse. The title bar is usually not displayed for
fullboth (see Size Parameters), tooltip (see Tooltips) and
child frames (see Child Frames) and doesn’t exist for terminal
frames. Display of the title bar can be suppressed by setting the
override-redirect or the undecorated frame parameters
(see Window Management Parameters).
The menu bar (see 菜单栏) can be either internal (drawn by Emacs
itself) or external (drawn by the toolkit). Most builds (GTK+, Lucid,
Motif and MS-Windows) rely on an external menu bar. NS also uses an
external menu bar which, however, is not part of the outer frame.
Non-toolkit builds can provide an internal menu bar. On text terminal
frames, the menu bar is part of the frame’s root window (see Windows and Frames). As a rule, menu bars are never shown on child frames
(see Child Frames). Display of the menu bar can be suppressed by
setting the menu-bar-lines parameter (see Layout Parameters)
to zero.
Whether the menu bar is wrapped or truncated whenever its width becomes too large to fit on its frame depends on the toolkit . Usually, only Motif and MS-Windows builds can wrap the menu bar. When they (un-)wrap the menu bar, they try to keep the outer height of the frame unchanged, so the native height of the frame (see below) will change instead.
Like the menu bar, the tool bar (see 工具栏) can be either
internal (drawn by Emacs itself) or external (drawn by a toolkit). The
GTK+ and NS builds have the tool bar drawn by the toolkit. The
remaining builds use internal tool bars. With GTK+ the tool bar can be
located on either side of the frame, immediately outside the internal
border, see below. Tool bars are usually not shown for child frames
(see Child Frames). Display of the tool bar can be suppressed by
setting the tool-bar-lines parameter (see Layout Parameters) to zero.
If the variable auto-resize-tool-bars is non-nil, Emacs
wraps the internal tool bar when its width becomes too large for its
frame. If and when Emacs (un-)wraps the internal tool bar, it by
default keeps the outer height of the frame unchanged, so the native
height of the frame (see below) will change instead. Emacs built with
GTK+, on the other hand, never wraps the tool bar but may
automatically increase the outer width of a frame in order to
accommodate an overlong tool bar.
The tab bar (see Tab Bars in The GNU Emacs Manual) is always
drawn by Emacs itself. The tab bar appears above the tool bar in
Emacs built with an internal tool bar, and below the tool bar in
builds with an external tool bar.
Display of the tab bar can be suppressed by setting the
tab-bar-lines parameter (see Layout Parameters) to zero.
The native frame is a rectangle located entirely within the outer frame. It excludes the areas occupied by an external or outer border, the title bar and any external menu or tool bar. The edges of the native frame are called the native edges of the frame. Together, the native width and native height of a frame specify the native size of the frame.
The native size of a frame is the size Emacs passes to the window-system or window manager when creating or resizing the frame from within Emacs. It is also the size Emacs receives from the window-system or window manager whenever these resize the frame’s window-system window, for example, after maximizing the frame by clicking on the corresponding button in the title bar or when dragging its external border with the mouse.
The position of the top left corner of the native frame specifies the native position of the frame. (1)–(3) in the drawing above indicate that position for the various builds:
Accordingly, the native height of a frame may include the height of the tool bar but not that of the menu bar (Lucid, Motif, MS-Windows) or those of the menu bar and the tool bar (non-toolkit and text terminal frames).
If the native position would otherwise be (2), but the tool bar is placed at the bottom of the frame as depicted in (4), the native position of the frame becomes that of the tab bar.
The native position of a frame is the reference position for functions
that set or return the current position of the mouse (see Mouse Position) and for functions dealing with the position of windows like
window-edges, window-at or coordinates-in-window-p
(see Coordinates and Windows). It also specifies the (0, 0) origin
for locating and positioning child frames within this frame
(see Child Frames).
Note also that the native position of a frame usually remains unaltered
on its display when removing or adding the window manager decorations by
changing the frame’s override-redirect or undecorated
parameter (see Window Management Parameters).
The internal border is a border drawn by Emacs around the inner frame (see below). The specification of its appearance depends on whether or not the given frame is a child frame (see Child Frames).
For normal frames its width is specified by the internal-border-width
frame parameter (see Layout Parameters), and its color is specified by the
background of the internal-border face.
For child frames its width is specified by the child-frame-border-width
frame parameter (but will use the internal-border-width parameter as
fallback), and its color is specified by the background of the
child-frame-border face.
The inner frame is the rectangle reserved for the frame’s windows. It’s enclosed by the internal border which, however, is not part of the inner frame. Its edges are called the inner edges of the frame. The inner width and inner height specify the inner size of the rectangle. The inner frame is sometimes also referred to as the display area of the frame.
As a rule, the inner frame is subdivided into the frame’s root window (see Windows and Frames) and the frame’s minibuffer window (see Minibuffer 窗口). There are two notable exceptions to this rule: A minibuffer-less frame contains a root window only and does not contain a minibuffer window. A minibuffer-only frame contains only a minibuffer window which also serves as that frame’s root window. See Initial Frame Parameters for how to create such frame configurations.
The text area of a frame is a somewhat fictitious area that can be embedded in the native frame. Its position is unspecified. Its width can be obtained by removing from that of the native width the widths of the internal border, one vertical scroll bar, and one left and one right fringe if they are specified for this frame, see Layout Parameters. Its height can be obtained by removing from that of the native height the widths of the internal border and the heights of the frame’s internal menu and tool bars, the tab bar and one horizontal scroll bar if specified for this frame.
The absolute position of a frame is given as a pair (X, Y) of horizontal and vertical pixel offsets relative to an origin (0, 0) of the frame’s display. Correspondingly, the absolute edges of a frame are given as pixel offsets from that origin.
Note that with multiple monitors, the origin of the display does not necessarily coincide with the top-left corner of the entire usable display area of the terminal. Hence the absolute position of a frame can be negative in such an environment even when that frame is completely visible.
By convention, vertical offsets increase “downwards”. This means that the height of a frame is obtained by subtracting the offset of its top edge from that of its bottom edge. Horizontal offsets increase “rightwards”, as expected, so a frame’s width is calculated by subtracting the offset of its left edge from that of its right edge.
For a frame on a graphical terminal the following function returns the sizes of the areas described above:
This function returns geometric attributes of frame. The return value is an association list of the attributes listed below. All coordinate, height and width values are integers counting pixels. Note that if frame has not been mapped yet, (see Visibility of Frames) some of the return values may only represent approximations of the actual values—those that can be seen after the frame has been mapped.
outer-positionA cons representing the absolute position of the outer frame, relative to the origin at position (0, 0) of frame’s display.
outer-sizeA cons of the outer width and height of frame.
external-border-sizeA cons of the horizontal and vertical width of frame’s external borders as supplied by the window manager. If the window manager doesn’t supply these values, Emacs will try to guess them from the coordinates of the outer and inner frame.
outer-border-widthThe width of the outer border of frame. The value is meaningful for non-GTK+ X builds only.
title-bar-sizeA cons of the width and height of the title bar of frame as supplied by the window manager or operating system. If both of them are zero, the frame has no title bar. If only the width is zero, Emacs was not able to retrieve the width information.
menu-bar-externalIf non-nil, this means the menu bar is external (not part of the
native frame of frame).
menu-bar-sizeA cons of the width and height of the menu bar of frame.
tool-bar-externalIf non-nil, this means the tool bar is external (not part of the
native frame of frame).
tool-bar-positionThis tells on which side the tool bar on frame is and can be one
of left, top, right or bottom.
The values left and right are only supported on builds
using the GTK+ toolkit; bottom is supported on all builds other
than NS, and top is supported everywhere.
tool-bar-sizeA cons of the width and height of the tool bar of frame.
internal-border-widthThe width of the internal border of frame.
The following function can be used to retrieve the edges of the outer, native and inner frame.
This function returns the absolute edges of the outer, native or inner
frame of frame. frame must be a live frame and defaults to
the selected one. The returned list has the form (left top right bottom) where all values are in pixels
relative to the origin of frame’s display. For terminal frames
the values returned for left and top are always zero.
Optional argument type specifies the type of the edges to return:
outer-edges means to return the outer edges of frame,
native-edges (or nil) means to return its native edges and
inner-edges means to return its inner edges.
By convention, the pixels of the display at the values returned for left and top are considered to be inside (part of) frame. Hence, if left and top are both zero, the pixel at the display’s origin is part of frame. The pixels at bottom and right, on the other hand, are considered to lie immediately outside frame. This means that if you have, for example, two side-by-side frames positioned such that the right outer edge of the frame on the left equals the left outer edge of the frame on the right, the pixels at that edge show a part of the frame on the right.
Each frame has a default font which specifies the default character size for that frame. This size is meant when retrieving or changing the size of a frame in terms of columns or lines (see Size Parameters). It is also used when resizing (see Window Sizes) or splitting (see Splitting Windows) windows.
The terms line height and canonical character height are sometimes used instead of “default character height”. Similarly, the terms column width and canonical character width are used instead of “default character width”.
These functions return the default height and width of a character in frame, measured in pixels. Together, these values establish the size of the default font on frame. The values depend on the choice of font for frame, see Font and Color Parameters.
The default font can be also set directly with the following function:
This sets the default font to font. When called interactively, it prompts for the name of a font, and uses that font on the selected frame. When called from Lisp, font should be a font name (a string), a font object, font entity, or a font spec.
If the optional argument keep-size is nil, this keeps the
number of frame lines and columns fixed. (If non-nil, the option
frame-inhibit-implied-resize described in the next section will
override this.) If keep-size is non-nil (or with a prefix
argument), it tries to keep the size of the display area of the current
frame fixed by adjusting the number of lines and columns.
If the optional argument frames is nil, this applies the
font to the selected frame only. If frames is non-nil, it
should be a list of frames to act upon, or t meaning all existing
and all future graphical frames.
On graphical systems, the position of a normal top-level frame is specified as the absolute position of its outer frame (see Frame Geometry). The position of a child frame (see Child Frames) is specified via pixel offsets of its outer edges relative to the native position of its parent frame.
You can access or change the position of a frame using the frame
parameters left and top (see Position Parameters).
Here are two additional functions for working with the positions of an
existing, visible frame. For both functions, the argument frame
must denote a live frame and defaults to the selected frame.
For a normal, non-child frame this function returns a cons of the pixel
coordinates of its outer position (see Frame Layout) with respect to
the origin (0, 0) of its display. For a child frame
(see Child Frames) this function returns the pixel coordinates of
its outer position with respect to an origin (0, 0) at the native
position of frame’s parent.
Negative values never indicate an offset from the right or bottom edge of frame’s display or parent frame. Rather, they mean that frame’s outer position is on the left and/or above the origin of its display or the native position of its parent frame. This usually means that frame is only partially visible (or completely invisible). However, on systems where the display’s origin does not coincide with its top-left corner, the frame may be visible on a secondary monitor.
On a text terminal frame both values are zero.
This function sets the outer frame position of frame to (x, y). The latter arguments specify pixels and normally count from the origin at the position (0, 0) of frame’s display. For child frames, they count from the native position of frame’s parent frame.
Negative parameter values position the right edge of the outer frame by -x pixels left from the right edge of the screen (or the parent frame’s native rectangle) and the bottom edge by -y pixels up from the bottom edge of the screen (or the parent frame’s native rectangle).
Note that negative values do not permit aligning the right or bottom
edge of frame exactly at the right or bottom edge of its display
or parent frame. Neither do they allow specifying a position that does
not lie within the edges of the display or parent frame. The frame
parameters left and top (see Position Parameters)
allow doing that, but may still fail to provide good results for the
initial or a new frame.
This function has no effect on text terminal frames.
This hook specifies the functions that are run when an Emacs frame is moved (assigned a new position) by the window-system or window manager. The functions are run with one argument, the frame that moved. For a child frame (see Child Frames), the functions are run only when the position of the frame changes in relation to that of its parent frame.
The canonical way to specify the size of a frame from within Emacs is by specifying its text size—a tuple of the width and height of the frame’s text area (see Frame Layout). It can be measured either in pixels or in terms of the frame’s canonical character size (see Frame Font).
For frames with an internal menu or tool bar, the frame’s native
height cannot be told exactly before the frame has been actually drawn.
This means that in general you cannot use the native size to specify the
initial size of a frame. As soon as you know the native size of a
visible frame, you can calculate its outer size (see Frame Layout)
by adding in the remaining components from the return value of
frame-geometry. For invisible frames or for frames that have
yet to be created, however, the outer size can only be estimated. This
also means that calculating an exact initial position of a frame
specified via offsets from the right or bottom edge of the screen
(see Frame Position) is impossible.
The text size of any frame can be set and retrieved with the help of
the height and width frame parameters (see Size Parameters). The text size of the initial frame can be also set with
the help of an X-style geometry specification. See Command Line Arguments for Emacs Invocation in The GNU Emacs
Manual. Below we list some functions to access and set the size of an
existing, visible frame, by default the selected one.
These functions return the height and width of the text area of
frame, measured in units of the default font height and width of
frame (see Frame Font). These functions are plain shorthands
for writing (frame-parameter frame 'height) and
(frame-parameter frame 'width).
If the text area of frame measured in pixels is not a multiple of its default font size, the values returned by these functions are rounded down to the number of characters of the default font that fully fit into the text area.
The functions following next return the pixel widths and heights of the native, outer and inner frame and the text area (see Frame Layout) of a given frame. For a text terminal, the results are in characters rather than pixels.
These functions return the outer width and height of frame in pixels.
These functions return the native width and height of frame in pixels.
These functions return the inner width and height of frame in pixels.
These functions return the width and height of the text area of frame in pixels.
On window systems that support it, Emacs tries by default to make the text size of a frame measured in pixels a multiple of the frame’s character size. This, however, usually means that a frame can be resized only in character size increments when dragging its external borders. It also may break attempts to truly maximize the frame or making it “fullheight” or “fullwidth” (see Size Parameters) leaving some empty space below and/or on the right of the frame. The following option may help in that case.
If this option is nil (the default), a frame’s text pixel size is
usually rounded to a multiple of the current values of that frame’s
frame-char-height and frame-char-width whenever the frame
is resized. If this is non-nil, no rounding occurs, hence frame
sizes can increase/decrease by one pixel.
Setting this variable usually causes the next resize operation to pass the corresponding size hints to the window manager. This means that this variable should be set only in a user’s initial file; applications should never bind it temporarily.
The precise meaning of a value of nil for this option depends on
the toolkit used. Dragging the external border with the mouse is done
character-wise provided the window manager is willing to process the
corresponding size hints. Calling set-frame-size (see below)
with arguments that do not specify the frame size as an integer multiple
of its character size, however, may: be ignored, cause a rounding
(GTK+), or be accepted (Lucid, Motif, MS-Windows).
With some window managers you may have to set this to non-nil in
order to make a frame appear truly maximized or full-screen.
This function sets the size of the text area of frame, measured in terms of the canonical height and width of a character on frame (see Frame Font).
The optional argument pixelwise non-nil means to measure
the new width and height in units of pixels instead. Note that if
frame-resize-pixelwise is nil, some toolkits may refuse to
truly honor the request if it does not increase/decrease the frame size
to a multiple of its character size.
This function resizes the text area of frame to a height of height lines. The sizes of existing windows in frame are altered proportionally to fit.
If pretend is non-nil, then Emacs displays height
lines of output in frame, but does not change its value for the
actual height of the frame. This is only useful on text terminals.
Using a smaller height than the terminal actually implements may be
useful to reproduce behavior observed on a smaller screen, or if the
terminal malfunctions when using its whole screen. Setting the frame
height directly does not always work, because knowing the correct
actual size may be necessary for correct cursor positioning on
text terminals.
The optional fourth argument pixelwise non-nil means that
frame should be height pixels high. Note that if
frame-resize-pixelwise is nil, some window managers may
refuse to truly honor the request if it does not increase/decrease the
frame height to a multiple of its character height.
When used interactively, this command will ask the user for the number of lines to set the height of the currently selected frame. You can also provide this value with a numeric prefix.
This function sets the width of the text area of frame, measured
in characters. The argument pretend has the same meaning as in
set-frame-height.
The optional fourth argument pixelwise non-nil means that
frame should be width pixels wide. Note that if
frame-resize-pixelwise is nil, some window managers may
refuse to fully honor the request if it does not increase/decrease the
frame width to a multiple of its character width.
When used interactively, this command will ask the user for the number of columns to set the width of the currently selected frame. You can also provide this value with a numeric prefix.
None of these three functions will make a frame smaller than needed to
display all of its windows together with their scroll bars, fringes,
margins, dividers, mode and header lines. This contrasts with requests
by the window manager triggered, for example, by dragging the external
border of a frame with the mouse. Such requests are always honored by
clipping, if necessary, portions that cannot be displayed at the right,
bottom corner of the frame. The parameters min-width and
min-height (see Size Parameters) can be used to obtain a
similar behavior when changing the frame size from within Emacs.
The abnormal hook window-size-change-functions (see Hooks for Window Scrolling and Changes) tracks all changes of the inner size of a frame including those
induced by request of the window-system or window manager. To rule out
false positives that might occur when changing only the sizes of a
frame’s windows without actually changing the size of the inner frame,
use the following function.
This function returns non-nil when the inner width or height of
frame has changed since window-size-change-functions was
run the last time for frame. It always returns nil
immediately after running window-size-change-functions for
frame.
By default, Emacs tries to keep the number of lines and columns of a frame’s text area unaltered when, for example, toggling its menu or tool bar, changing its default font or setting the width of any of its scroll bars. This means that in such case Emacs must ask the window manager to resize the frame’s window in order to accommodate the size change.
Occasionally, such implied frame resizing may be unwanted, for example, when a frame has been maximized or made full-screen (where it’s turned off by default). In general, users can disable implied resizing with the following option:
If this option is nil, changing a frame’s font, menu bar, tool
bar, internal borders, fringes or scroll bars may resize its outer
frame in order to keep the number of columns or lines of its text area
unaltered. If this option is t, no such resizing is done.
The value of this option can be also a list of frame parameters. In
that case, implied resizing is inhibited for the change of a parameter
that appears in this list. Parameters currently handled by this
option are font, font-backend,
internal-border-width, menu-bar-lines and
tool-bar-lines.
Changing any of the scroll-bar-width, scroll-bar-height,
vertical-scroll-bars, horizontal-scroll-bars,
left-fringe and right-fringe frame parameters is handled
as if the frame contained just one live window. This means, for
example, that removing vertical scroll bars on a frame containing
several side by side windows will shrink the outer frame width by the
width of one scroll bar provided this option is nil and keep it
unchanged if this option is t or a list containing
vertical-scroll-bars.
The default value is (tab-bar-lines tool-bar-lines) for Lucid,
Motif and MS-Windows (which means that adding/removing a tool or tab
bar there does not change the outer frame height),
(tab-bar-lines) on all other window systems including GTK+
(which means that changing any of the parameters listed above with the
exception of tab-bar-lines may change the size of the outer
frame), and t otherwise (which means the outer frame size never
changes implicitly when there’s no window system support).
Note that when a frame is not large enough to accommodate a change of
any of the parameters listed above, Emacs may try to enlarge the frame
even if this option is non-nil.
Note also that window managers usually do not ask for resizing a frame when they change the number of lines occupied by an external menu or tool bar. Typically, such “wrappings” occur when a user shrinks a frame horizontally, making it impossible to display all elements of its menu or tool bar. They may also result from a change of the major mode altering the number of items of a menu or tool bar. Any such wrappings may implicitly alter the number of lines of a frame’s text area and are unaffected by the setting of this option.
A frame has many parameters that control its appearance and behavior. Just what parameters a frame has depends on what display mechanism it uses.
Frame parameters exist mostly for the sake of graphical displays.
Most frame parameters have no effect when applied to a frame on a text
terminal; only the height, width, name,
title, menu-bar-lines, buffer-list and
buffer-predicate parameters do something special. If the
terminal supports colors, the parameters foreground-color,
background-color, background-mode and
display-type are also meaningful. If the terminal supports
frame transparency, the parameter alpha is also meaningful.
By default, frame parameters are saved and restored by the desktop
library functions (see 桌面保存模式) when the variable
desktop-restore-frames is non-nil. It’s the
responsibility of applications that their parameters are included in
frameset-persistent-filter-alist to avoid that they get
meaningless or even harmful values in restored sessions.
These functions let you read and change the parameter values of a frame.
This function returns the value of the parameter parameter (a
symbol) of frame. If frame is nil, it returns the
selected frame’s parameter. If frame has no setting for
parameter, this function returns nil.
The function frame-parameters returns an alist listing all the
parameters of frame and their values. If frame is
nil or omitted, this returns the selected frame’s parameters
This function alters the frame frame based on the elements of
alist. Each element of alist has the form
(parm . value), where parm is a symbol naming
a parameter. If you don’t mention a parameter in alist, its
value doesn’t change. If frame is nil, it defaults to
the selected frame.
Some parameters are only meaningful for frames on certain kinds of display (see Frames). If alist includes parameters that are not meaningful for the frame’s display, this function will change its value in the frame’s parameter list, but will otherwise ignore it.
When alist specifies more than one parameter whose value can affect the new size of frame, the final size of the frame may differ according to the toolkit used. For example, specifying that a frame should from now on have a menu and/or tool bar instead of none and simultaneously specifying the new height of the frame will inevitably lead to a recalculation of the frame’s height. Conceptually, in such case, this function will try to have the explicit height specification prevail. It cannot be excluded, however, that the addition (or removal) of the menu or tool bar, when eventually performed by the toolkit, will defeat this intention.
Sometimes, binding frame-inhibit-implied-resize (see Implied Frame Resizing) to a non-nil value around calls to this function
may fix the problem sketched here. Sometimes, however, exactly such
binding may be hit by the problem.
This function sets the frame parameter parm to the specified
value. If frame is nil, it defaults to the selected
frame.
This function alters the frame parameters of all existing frames
according to alist, then modifies default-frame-alist
(and, if necessary, initial-frame-alist) to apply the same
parameter values to frames that will be created henceforth.
You can specify the parameters for the initial startup frame by
setting initial-frame-alist in your init file (see The Init File).
This variable’s value is an alist of parameter values used when creating the initial frame. You can set this variable to specify the appearance of the initial frame without altering subsequent frames. Each element has the form:
(parameter . value)
Emacs creates the initial frame before it reads your init
file. After reading that file, Emacs checks initial-frame-alist,
and applies the parameter settings in the altered value to the already
created initial frame.
If these settings affect the frame geometry and appearance, you’ll see the frame appear with the wrong ones and then change to the specified ones. If that bothers you, you can specify the same geometry and appearance with X resources; those do take effect before the frame is created. See X Resources in The GNU Emacs Manual.
X resource settings typically apply to all frames. If you want to
specify some X resources solely for the sake of the initial frame, and
you don’t want them to apply to subsequent frames, here’s how to achieve
this. Specify parameters in default-frame-alist to override the
X resources for subsequent frames; then, to prevent these from affecting
the initial frame, specify the same parameters in
initial-frame-alist with values that match the X resources.
If these parameters include (minibuffer . nil), that indicates
that the initial frame should have no minibuffer. In this case, Emacs
creates a separate minibuffer-only frame as well.
This variable’s value is an alist of parameter values used when
creating an initial minibuffer-only frame (i.e., the minibuffer-only
frame that Emacs creates if initial-frame-alist specifies a
frame with no minibuffer).
This is an alist specifying default values of frame parameters for all Emacs frames—the first frame, and subsequent frames. When using the X Window System, you can get the same results by means of X resources in many cases.
Setting this variable does not affect existing frames. Furthermore, functions that display a buffer in a separate frame may override the default parameters by supplying their own parameters.
If you invoke Emacs with command-line options that specify frame
appearance, those options take effect by adding elements to either
initial-frame-alist or default-frame-alist. Options
which affect just the initial frame, such as ‘--geometry’ and
‘--maximized’, add to initial-frame-alist; the others add
to default-frame-alist. see Command Line
Arguments for Emacs Invocation in The GNU Emacs Manual.
Just what parameters a frame has depends on what display mechanism
it uses. This section describes the parameters that have special
meanings on some or all kinds of terminals. Of these, name,
title, height, width, buffer-list and
buffer-predicate provide meaningful information in terminal
frames, and tty-color-mode is meaningful only for frames on
text terminals.
These frame parameters give the most basic information about the
frame. title and name are meaningful on all terminals.
display ¶The display on which to open this frame. It should be a string of the
form ‘host:dpy.screen’, just like the
DISPLAY environment variable. See Multiple Terminals, for
more details about display names.
display-type ¶This parameter describes the range of possible colors that can be used
in this frame. Its value is color, grayscale or
mono.
title ¶If a frame has a non-nil title, that title appears in the window
system’s title bar at the top of the frame, and also in the mode line
of windows in that frame if mode-line-frame-identification uses
‘%F’ (see 模式行中的 %-constucts). This is normally the case when
Emacs is not using a window system, and can only display one frame at
a time. When Emacs is using a window system, this parameter, if
non-nil, overrides the title determined by the name
parameter and the implicit title calculated according to
frame-title-format. It also overrides the title determined by
icon-title-format for iconified frames. See Frame Titles.
name ¶The name of the frame. If you don’t specify a name via this
parameter, Emacs sets the frame name automatically, as specified by
frame-title-format and icon-title-format, and that is
the frame’s title that will appear on display when Emacs uses a window
system (unless the title parameter overrides it).
If you specify the frame name explicitly when you create the frame, the name is also used (instead of the name of the Emacs executable) when looking up X resources for the frame.
explicit-name ¶If the frame name was specified explicitly when the frame was created,
this parameter will be that name. If the frame wasn’t explicitly
named, this parameter will be nil.
Parameters describing the X- and Y-offsets of a frame are always measured in pixels. For a normal, non-child frame they specify the frame’s outer position (see Frame Geometry) relative to its display’s origin. For a child frame (see Child Frames) they specify the frame’s outer position relative to the native position of the frame’s parent frame. (Note that none of these parameters is meaningful on TTY frames.)
left ¶The position, in pixels, of the left outer edge of the frame with respect to the left edge of the frame’s display or parent frame. It can be specified in one of the following ways.
A positive integer always relates the left edge of the frame to the left edge of its display or parent frame. A negative integer relates the right frame edge to the right edge of the display or parent frame.
(+ pos)This specifies the position of the left frame edge relative to the left edge of its display or parent frame. The integer pos may be positive or negative; a negative value specifies a position outside the screen or parent frame or on a monitor other than the primary one (for multi-monitor displays).
(- pos)This specifies the position of the right frame edge relative to the right edge of the display or parent frame. The integer pos may be positive or negative; a negative value specifies a position outside the screen or parent frame or on a monitor other than the primary one (for multi-monitor displays).
A floating-point value in the range 0.0 to 1.0 specifies the left edge’s offset via the left position ratio of the frame—the ratio of the left edge of its outer frame to the width of the frame’s workarea (see Multiple Terminals) or its parent’s native frame (see Child Frames) minus the width of the outer frame. Thus, a left position ratio of 0.0 flushes a frame to the left, a ratio of 0.5 centers it and a ratio of 1.0 flushes it to the right of its display or parent frame. Similarly, the top position ratio of a frame is the ratio of the frame’s top position to the height of its workarea or parent frame minus the height of the frame.
Emacs will try to keep the position ratios of a child frame unaltered if
that frame has a non-nil keep-ratio parameter
(see Frame Interaction Parameters) and its parent frame is resized.
Since the outer size of a frame (see Frame Geometry) is usually unavailable before a frame has been made visible, it is generally not advisable to use floating-point values when creating decorated frames. Floating-point values are more suited for ensuring that an (undecorated) child frame is positioned nicely within the area of its parent frame.
Some window managers ignore program-specified positions. If you want to
be sure the position you specify is not ignored, specify a
non-nil value for the user-position parameter as in the
following example:
(modify-frame-parameters nil '((user-position . t) (left . (+ -4))))
In general, it is not a good idea to position a frame relative to the right or bottom edge of its display. Positioning the initial or a new frame is either not accurate (because the size of the outer frame is not yet fully known before the frame has been made visible) or will cause additional flicker (if the frame has to be repositioned after becoming visible).
Note also, that positions specified relative to the right/bottom edge
of a display, workarea or parent frame as well as floating-point offsets
are stored internally as integer offsets relative to the left/top edge
of the display, workarea or parent frame edge. They are also returned
as such by functions like frame-parameters and restored as such
by the desktop saving routines.
top ¶The screen position of the top (or bottom) edge, in pixels, with respect
to the top (or bottom) edge of the display or parent frame. It works
just like left, except vertically instead of horizontally.
icon-left ¶The screen position of the left edge of the frame’s icon, in pixels,
counting from the left edge of the screen. This takes effect when the
frame is iconified, if the window manager supports this feature. If
you specify a value for this parameter, then you must also specify a
value for icon-top and vice versa.
icon-top ¶The screen position of the top edge of the frame’s icon, in pixels, counting from the top edge of the screen. This takes effect when the frame is iconified, if the window manager supports this feature.
user-position ¶When you create a frame and specify its screen position with the
left and top parameters, use this parameter to say whether
the specified position was user-specified (explicitly requested in some
way by a human user) or merely program-specified (chosen by a program).
A non-nil value says the position was user-specified.
Window managers generally heed user-specified positions, and some heed
program-specified positions too. But many ignore program-specified
positions, placing the window in a default fashion or letting the user
place it with the mouse. Some window managers, including twm,
let the user specify whether to obey program-specified positions or
ignore them.
When you call make-frame, you should specify a non-nil
value for this parameter if the values of the left and top
parameters represent the user’s stated preference; otherwise, use
nil.
z-group ¶This parameter specifies a relative position of the frame’s window-system window in the stacking (Z-) order of the frame’s display.
If this is above, the window-system will display the window
that corresponds to the frame above all other window-system windows
that do not have the above property set. If this is
nil, the frame’s window is displayed below all windows that
have the above property set and above all windows that have the
below property set. If this is below, the frame’s
window is displayed below all windows that do not have the
below property set.
To position the frame above or below a specific other frame use the
function frame-restack (see Raising, Lowering and Restacking Frames).
Frame parameters usually specify frame sizes in character units. On
graphical displays, the default face determines the actual pixel
sizes of these character units (see Face Attributes).
width ¶This parameter specifies the width of the frame. It can be specified as in the following ways:
A positive integer specifies the width of the frame’s text area (see Frame Geometry) in characters.
If this is a cons cell with the symbol text-pixels in its
CAR, the CDR of that cell specifies the width of the frame’s
text area in pixels.
A floating-point number between 0.0 and 1.0 can be used to specify the width of a frame via its width ratio—the ratio of its outer width (see Frame Geometry) to the width of the frame’s workarea (see Multiple Terminals) or its parent frame’s (see Child Frames) native frame. Thus, a value of 0.5 makes the frame occupy half of the width of its workarea or parent frame, a value of 1.0 the full width. Similarly, the height ratio of a frame is the ratio of its outer height to the height of its workarea or its parent’s native frame.
Emacs will try to keep the width and height ratio of a child frame
unaltered if that frame has a non-nil keep-ratio parameter
(see Frame Interaction Parameters) and its parent frame is resized.
Since the outer size of a frame is usually unavailable before a frame
has been made visible, it is generally not advisable to use
floating-point values when creating decorated frames. Floating-point
values are more suited to ensure that a child frame always fits within
the area of its parent frame as, for example, when customizing
display-buffer-alist (see Choosing a Window for Displaying a Buffer) via
display-buffer-in-child-frame.
Regardless of how this parameter was specified, functions reporting the
value of this parameter like frame-parameters always report the
width of the frame’s text area in characters as an integer rounded, if
necessary, to a multiple of the frame’s default character width. That
value is also used by the desktop saving routines.
height ¶This parameter specifies the height of the frame. It works just like
width, except vertically instead of horizontally.
user-size ¶This does for the size parameters height and width what
the user-position parameter (see user-position) does for the position parameters top and
left.
min-width ¶This parameter specifies the minimum native width (see Frame Geometry) of the frame, in characters. Normally, the functions that
establish a frame’s initial width or resize a frame horizontally make
sure that all the frame’s windows, vertical scroll bars, fringes,
margins and vertical dividers can be displayed. This parameter, if
non-nil enables making a frame narrower than that with the
consequence that any components that do not fit will be clipped by the
window manager.
min-height ¶This parameter specifies the minimum native height (see Frame Geometry) of the frame, in characters. Normally, the functions that
establish a frame’s initial size or resize a frame make sure that all
the frame’s windows, horizontal scroll bars and dividers, mode and
header lines, the echo area and the internal menu and tool bar can be
displayed. This parameter, if non-nil enables making a frame
smaller than that with the consequence that any components that do not
fit will be clipped by the window manager.
fullscreen ¶This parameter specifies whether to maximize the frame’s width, height
or both. Its value can be fullwidth, fullheight,
fullboth, or maximized.22 A
fullwidth frame is as wide as possible, a fullheight frame
is as tall as possible, and a fullboth frame is both as wide and
as tall as possible. A maximized frame is like a “fullboth”
frame, except that it usually keeps its title bar and the buttons for
resizing and closing the frame. Also, maximized frames typically
avoid hiding any task bar or panels displayed on the desktop. A
“fullboth” frame, on the other hand, usually omits the title bar and
occupies the entire available screen space.
Full-height and full-width frames are more similar to maximized frames in this regard. However, these typically display an external border which might be absent with maximized frames. Hence the heights of maximized and full-height frames and the widths of maximized and full-width frames often differ by a few pixels.
With some window managers you may have to customize the variable
frame-resize-pixelwise (see Frame Size) in order to make a
frame truly appear maximized or full-screen. Moreover, some window
managers might not support smooth transition between the various
full-screen or maximization states. Customizing the variable
x-frame-normalize-before-maximize can help to overcome that.
Full-screen on macOS hides both the tool-bar and the menu-bar, however both will be displayed if the mouse pointer is moved to the top of the screen.
fullscreen-restore ¶This parameter specifies the desired fullscreen state of the frame
after invoking the toggle-frame-fullscreen command (see Frame
Commands in The GNU Emacs Manual) in the “fullboth” state.
Normally this parameter is installed automatically by that command when
toggling the state to fullboth. If, however, you start Emacs in the
“fullboth” state, you have to specify the desired behavior in your initial
file as, for example
(setq default-frame-alist
'((fullscreen . fullboth)
(fullscreen-restore . fullheight)))
This will give a new frame full height after typing in it F11 for the first time.
fit-frame-to-buffer-margins ¶This parameter enables overriding the value of the option
fit-frame-to-buffer-margins when fitting this frame to the
buffer of its root window with fit-frame-to-buffer
(see Resizing Windows).
fit-frame-to-buffer-sizes ¶This parameter enables overriding the value of the option
fit-frame-to-buffer-sizes when fitting this frame to the buffer
of its root window with fit-frame-to-buffer (see Resizing Windows).
These frame parameters enable or disable various parts of the frame, or control their sizes.
border-width ¶The width in pixels of the frame’s outer border (see Frame Geometry).
internal-border-width ¶The width in pixels of the frame’s internal border (see Frame Geometry).
child-frame-border-width ¶The width in pixels of the frame’s internal border (see Frame Geometry) if the given frame is a child frame (see Child Frames).
If this is nil, the value specified by the
internal-border-width parameter is used instead.
vertical-scroll-bars ¶Whether the frame has scroll bars (see Scroll Bars) for vertical
scrolling, and which side of the frame they should be on. The possible
values are left, right, and nil for no scroll bars.
horizontal-scroll-bars ¶Whether the frame has scroll bars for horizontal scrolling (t and
bottom mean yes, nil means no).
scroll-bar-width ¶The width of vertical scroll bars, in pixels, or nil meaning to
use the default width.
scroll-bar-height ¶The height of horizontal scroll bars, in pixels, or nil meaning
to use the default height.
left-fringe ¶right-fringeThe default width of the left and right fringes of windows in this frame (see Fringes). If either of these is zero, that effectively removes the corresponding fringe.
When you use frame-parameter to query the value of either of
these two frame parameters, the return value is always an integer.
When using set-frame-parameter, passing a nil value
imposes an actual default value of 8 pixels.
right-divider-width ¶The width (thickness) reserved for the right divider (see Window Dividers) of any window on the frame, in pixels. A value of zero means to not draw right dividers.
bottom-divider-width ¶The width (thickness) reserved for the bottom divider (see Window Dividers) of any window on the frame, in pixels. A value of zero means to not draw bottom dividers.
menu-bar-lines ¶The number of lines to allocate at the top of the frame for a menu bar
(see 菜单栏). The default is one if Menu Bar mode is enabled
and zero otherwise. See Menu Bars in The GNU Emacs Manual.
For an external menu bar (see Frame Layout), this value remains
unchanged even when the menu bar wraps to two or more lines. In that
case, the menu-bar-size value returned by frame-geometry
(see Frame Geometry) enables you to establish whether the menu bar
actually occupies one or more lines.
tool-bar-lines ¶The number of lines to use for the tool bar (see 工具栏). The default is one if Tool Bar mode is enabled and zero otherwise. See Tool Bars in The GNU Emacs Manual. This value may change whenever the tool bar wraps (see Frame Layout).
tool-bar-position ¶The position of the tool bar. Its value can be one of top,
bottom left, right. The default is top.
It can be set to bottom on Emacs built with any toolkit other
than Nextstep, and left or right on builds using GTK+.
tab-bar-lines ¶The number of lines to use for the tab bar (see Tab Bars in The GNU Emacs Manual). The default is one if Tab Bar mode is enabled and zero otherwise. This value may change whenever the tab bar wraps (see Frame Layout).
line-spacing ¶Additional space to leave below each text line, in pixels (a positive integer). See Line Height, for more information.
no-special-glyphs ¶If this is non-nil, it suppresses the display of any truncation
(see Truncation) and continuation glyphs for all the buffers
displayed by this frame. This is useful to eliminate such glyphs when
fitting a frame to its buffer via fit-frame-to-buffer
(see Resizing Windows). This frame parameter has effect only for
GUI frames shown on graphical displays, and only if the fringes are
disabled. This parameter is intended as a purely-presentation
feature, and in particular should not be used for frames where the
user can interactively insert text, or more generally where the cursor
is shown. A notable example of frames where this is used is tooltip
frames (see Tooltips).
These frame parameters, meaningful on all kinds of terminals, deal with which buffers have been, or should, be displayed in the frame.
minibuffer ¶Whether this frame has its own minibuffer. The value t means
yes, nil means no, only means this frame is just a
minibuffer. If the value is a minibuffer window (in some other
frame), the frame uses that minibuffer.
This parameter takes effect when the frame is created. If specified as
nil, Emacs will try to set it to the minibuffer window of
default-minibuffer-frame (see Minibuffers and Frames). For
an existing frame, this parameter can be used exclusively to specify
another minibuffer window. It is not allowed to change it from a
minibuffer window to t and vice-versa, or from t to
nil. If the parameter specifies a minibuffer window already,
setting it to nil has no effect.
The special value child-frame means to make a minibuffer-only
child frame (see Child Frames) whose parent becomes the frame
created. As if specified as nil, Emacs will set this parameter
to the minibuffer window of the child frame but will not select the
child frame after its creation.
buffer-predicate ¶The buffer-predicate function for this frame. The function
other-buffer uses this predicate (from the selected frame) to
decide which buffers it should consider, if the predicate is not
nil. It calls the predicate with one argument, a buffer, once for
each buffer; if the predicate returns a non-nil value, it
considers that buffer.
buffer-list ¶A list of buffers that have been selected in this frame, ordered most-recently-selected first.
unsplittable ¶If non-nil, this frame’s window is never split automatically.
These parameters supply forms of interactions between different frames.
parent-frame ¶If non-nil, this means that this frame is a child frame
(see Child Frames), and this parameter specifies its parent frame.
If nil, this means that this frame is a normal, top-level frame.
delete-before ¶If non-nil, this parameter specifies another frame whose deletion
will automatically trigger the deletion of this frame. See Deleting Frames.
mouse-wheel-frame ¶If non-nil, this parameter specifies the frame whose windows will
be scrolled whenever the mouse wheel is scrolled with the mouse pointer
hovering over this frame, see Mouse Commands in The GNU
Emacs Manual.
no-other-frame ¶If this is non-nil, then this frame is not eligible as candidate
for the functions next-frame, previous-frame
(see Finding All Frames) and other-frame, see Frame
Commands in The GNU Emacs Manual.
auto-hide-function ¶When this parameter specifies a function, that function will be called
instead of the function specified by the variable
frame-auto-hide-function when quitting the frame’s only window
(see Quitting Windows) and there are other frames left.
minibuffer-exit ¶When this parameter is non-nil, Emacs will by default make this
frame invisible whenever the minibuffer (see 迷你缓冲区) is exited.
Alternatively, it can specify the functions iconify-frame and
delete-frame. This parameter is useful to make a child frame
disappear automatically (similar to how Emacs deals with a window) when
exiting the minibuffer.
keep-ratio ¶This parameter is currently meaningful for child frames (see Child Frames) only. If it is non-nil, then Emacs will try to keep the
frame’s size (width and height) ratios (see Size Parameters) as well
as its left and right position ratios (see Position Parameters)
unaltered whenever its parent frame is resized.
If the value of this parameter is nil, the frame’s position and
size remain unaltered when the parent frame is resized, so the position
and size ratios may change. If the value of this parameter is t,
Emacs will try to preserve the frame’s size and position ratios, hence
the frame’s size and position relative to its parent frame may change.
More individual control is possible by using a cons cell: In that case
the frame’s width ratio is preserved if the CAR of the cell is
either t or width-only. The height ratio is preserved if
the CAR of the cell is either t or height-only. The
left position ratio is preserved if the CDR of the cell is either
t or left-only. The top position ratio is preserved if
the CDR of the cell is either t or top-only.
The parameters described below provide support for resizing a frame by dragging its internal borders with the mouse. They also allow moving a frame with the mouse by dragging the header or tab line of its topmost or the mode line of its bottommost window.
These parameters are mostly useful for child frames (see Child Frames) that come without window manager decorations. If necessary, they can be used for undecorated top-level frames as well.
drag-internal-border ¶If non-nil, the frame can be resized by dragging its internal
borders, if present, with the mouse.
drag-with-header-line ¶If non-nil, the frame can be moved with the mouse by dragging the
header line of its topmost window.
drag-with-tab-line ¶If non-nil, the frame can be moved with the mouse by dragging the
tab line of its topmost window.
drag-with-mode-line ¶If non-nil, the frame can be moved with the mouse by dragging the
mode line of its bottommost window. Note that such a frame is not
allowed to have its own minibuffer window.
snap-width ¶A frame that is moved with the mouse will “snap” at the border(s) of the display or its parent frame whenever it is dragged as near to such an edge as the number of pixels specified by this parameter.
top-visible ¶If this parameter is a number, the top edge of the frame never appears
above the top edge of its display or parent frame. Moreover, as many
pixels of the frame as specified by that number will remain visible when
the frame is moved against any of the remaining edges of its display or
parent frame. Setting this parameter is useful to guard against
dragging a child frame with a non-nil
drag-with-header-line parameter completely out of the area
of its parent frame.
bottom-visible ¶If this parameter is a number, the bottom edge of the frame never
appears below the bottom edge of its display or parent frame. Moreover,
as many pixels of the frame as specified by that number will remain
visible when the frame is moved against any of the remaining edges of
its display or parent frame. Setting this parameter is useful to guard
against dragging a child frame with a non-nil
drag-with-mode-line parameter completely out of the area of
its parent frame.
The following frame parameters control various aspects of the frame’s interaction with the window manager or window system. They have no effect on text terminals.
visibility ¶The state of visibility of the frame. There are three possibilities:
nil for invisible, t for visible, and icon for
iconified. See Visibility of Frames.
auto-raise ¶If non-nil, Emacs automatically raises the frame when it is
selected. Some window managers do not allow this.
auto-lower ¶If non-nil, Emacs automatically lowers the frame when it is
deselected. Some window managers do not allow this.
icon-type ¶The type of icon to use for this frame. If the value is a string,
that specifies a file containing a bitmap to use; nil specifies
no icon (in which case the window manager decides what to show); any
other non-nil value specifies the default Emacs icon.
icon-name ¶The name to use in the icon for this frame, when and if the icon
appears. If this is nil, the frame’s title is used.
window-id ¶The ID number which the graphical display uses for this frame. Emacs assigns this parameter when the frame is created; changing the parameter has no effect on the actual ID number.
outer-window-id ¶The ID number of the outermost window-system window in which the frame
exists. As with window-id, changing this parameter has no
actual effect.
wait-for-wm ¶If non-nil, tell Xt to wait for the window manager to confirm
geometry changes. Some window managers, including versions of Fvwm2
and KDE, fail to confirm, so Xt hangs. Set this to nil to
prevent hanging with those window managers.
sticky ¶If non-nil, the frame is visible on all virtual desktops on systems
with virtual desktops.
shaded ¶If non-nil, tell the window manager to display the frame in a
way that its contents are hidden, leaving only the title bar.
use-frame-synchronization ¶If non-nil, synchronize the frame redisplay with the refresh
rate of the monitor to avoid graphics tearing. At present, this is
only implemented on Haiku and the X window system inside no-toolkit
and X toolkit builds, does not work correctly with toolkit scroll
bars, and requires a compositing manager supporting the relevant
display synchronization protocols. The synchronizeResize X
resource must also be set to the string "extended".
inhibit-double-buffering ¶If non-nil, the frame is drawn to the screen without double
buffering. Emacs normally attempts to use double buffering, where
available, to reduce flicker; nevertheless, this parameter is provided
for circumstances where double-buffering induces display corruption,
and for those eccentrics wistful for the immemorial flicker that once
beset Emacs.
skip-taskbar ¶If non-nil, this tells the window manager to remove the frame’s
icon from the taskbar associated with the frame’s display and inhibit
switching to the frame’s window via the combination Alt-TAB.
On MS-Windows, iconifying such a frame will "roll in" its window-system
window at the bottom of the desktop. Some window managers may not honor
this parameter.
no-focus-on-map ¶If non-nil, this means that the frame does not want to receive
input focus when it is mapped (see Visibility of Frames). Some
window managers may not honor this parameter.
no-accept-focus ¶If non-nil, this means that the frame does not want to receive
input focus via explicit mouse clicks or when moving the mouse into it
either via focus-follows-mouse (see Input Focus) or
mouse-autoselect-window (see Mouse Window Auto-selection).
This may have the unwanted side-effect that a user cannot scroll a
non-selected frame with the mouse. Some window managers may not honor
this parameter. On Haiku, it also has the side-effect that the window
will not be able to receive any keyboard input from the user, not even
if the user switches to the frame using the key combination
Alt-TAB.
undecorated ¶If non-nil, this frame’s window-system window is drawn without
decorations, like the title, minimize/maximize boxes and external
borders. This usually means that the window cannot be dragged, resized,
iconified, maximized or deleted with the mouse. If nil, the frame’s
window is usually drawn with all the elements listed above unless their
display has been suspended via window manager settings.
Under X, Emacs uses the Motif window manager hints to turn off decorations. Some window managers may not honor these hints.
NS builds consider the tool bar to be a decoration, and therefore hide it on an undecorated frame.
override-redirect ¶If non-nil, this means that this is an override redirect
frame—a frame not handled by window managers under X. Override
redirect frames have no window manager decorations, can be positioned
and resized only via Emacs’s positioning and resizing functions and are
usually drawn on top of all other frames. Setting this parameter has
no effect on MS-Windows.
ns-appearance ¶Only available on macOS, if set to dark draw this frame’s
window-system window using the “vibrant dark” theme, and if set to
light use the “aqua” theme, otherwise use the system default.
The “vibrant dark” theme can be used to set the toolbar and
scrollbars to a dark appearance when using an Emacs theme with a dark
background.
ns-transparent-titlebar ¶Only available on macOS, if non-nil, set the titlebar and
toolbar to be transparent. This effectively sets the background color
of both to match the Emacs background color.
This frame parameter controls the way the cursor looks.
cursor-type ¶How to display the cursor. Legitimate values are:
boxDisplay a filled box. (This is the default.)
(box . size)Display a filled box. However, display it as a hollow box if point is under masked image larger than size pixels in either dimension.
hollowDisplay a hollow box.
nilDon’t display a cursor.
barDisplay a vertical bar between characters.
(bar . width)Display a vertical bar width pixels wide between characters.
hbarDisplay a horizontal bar.
(hbar . height)Display a horizontal bar height pixels high.
The cursor-type frame parameter may be overridden by
set-window-cursor-type (see Windows and Point), and by the
variables cursor-type and cursor-in-non-selected-windows:
This buffer-local variable controls how the cursor looks in a selected
window showing the buffer. If its value is t, that means to
use the cursor specified by the cursor-type frame parameter.
Otherwise, the value should be one of the cursor types listed above,
and it overrides the cursor-type frame parameter.
This buffer-local variable controls how the cursor looks in a window
that is not selected. It supports the same values as the
cursor-type frame parameter; also, nil means don’t
display a cursor in nonselected windows, and t (the default)
means use a standard modification of the usual cursor type (solid box
becomes hollow box, and bar becomes a narrower bar).
This variable controls the width of the block cursor displayed on
extra-wide glyphs such as a tab or a stretch of white space. By
default, the block cursor is only as wide as the font’s default
character, and will not cover all of the width of the glyph under it
if that glyph is extra-wide. A non-nil value of this variable
means draw the block cursor as wide as the glyph under it. The
default value is nil.
This variable has no effect on text-mode frames, since the text-mode cursor is drawn by the terminal out of Emacs’s control.
This variable specifies how to blink the cursor. Each element has the
form (on-state . off-state). Whenever the cursor
type equals on-state (comparing using equal), the
corresponding off-state specifies what the cursor looks like
when it blinks off. Both on-state and off-state
should be suitable values for the cursor-type frame parameter.
There are various defaults for how to blink each type of cursor, if
the type is not mentioned as an on-state here. Changes in this
variable do not take effect immediately, only when you specify the
cursor-type frame parameter.
These frame parameters control the use of fonts and colors.
font-backend ¶A list of symbols, specifying the font backends to use for
drawing characters on the frame, in order of priority. In Emacs built
without Cairo drawing on X, there are currently three potentially
available font backends: x (the X core font driver), xft
(the Xft font driver), and xfthb (the Xft font driver with
HarfBuzz text shaping). If built with Cairo drawing, there are also
three potentially available font backends on X: x, ftcr
(the FreeType font driver on Cairo), and ftcrhb (the FreeType
font driver on Cairo with HarfBuzz text shaping). When Emacs is built
with HarfBuzz, the default font driver is ftcrhb, although use
of the ftcr driver is still possible, but not recommended. On
MS-Windows, there are currently three available font backends:
gdi (the core MS-Windows font driver), uniscribe (font
driver for OTF and TTF fonts with text shaping by the Uniscribe
engine), and harfbuzz (font driver for OTF and TTF fonts with
HarfBuzz text shaping) (see Windows Fonts in The GNU Emacs
Manual). The harfbuzz driver is similarly recommended. On
Haiku, there can be several font drivers (see Haiku Fonts in The GNU Emacs Manual), as on Android (see Android Fonts in The GNU Emacs Manual).
On other systems, there is only one available font backend, so it does not make sense to modify this frame parameter.
background-mode ¶This parameter is either dark or light, according
to whether the background color is a light one or a dark one.
tty-color-mode ¶This parameter overrides the terminal’s color support as given by the
system’s terminal capabilities database in that this parameter’s value
specifies the color mode to use on a text terminal. The value can be
either a symbol or a number. A number specifies the number of colors
to use (and, indirectly, what commands to issue to produce each
color). For example, (tty-color-mode . 8) specifies use of the
ANSI escape sequences for 8 standard text colors. A value of −1 turns
off color support.
If the parameter’s value is a symbol, it specifies a number through
the value of tty-color-mode-alist, and the associated number is
used instead. This parameter supports dynamic changes during a running
Emacs session (but not on MS-Windows and MS-DOS).
screen-gamma ¶If this is a number, Emacs performs gamma correction which adjusts the brightness of all colors. The value should be the screen gamma of your display.
Usual PC monitors have a screen gamma of 2.2, so color values in
Emacs, and in X windows generally, are calibrated to display properly
on a monitor with that gamma value. If you specify 2.2 for
screen-gamma, that means no correction is needed. Other values
request correction, designed to make the corrected colors appear on
your screen the way they would have appeared without correction on an
ordinary monitor with a gamma value of 2.2.
If your monitor displays colors too light, you should specify a
screen-gamma value smaller than 2.2. This requests correction
that makes colors darker. A screen gamma value of 1.5 may give good
results for LCD color displays.
alpha ¶This parameter specifies the opacity of the frame, on graphical
displays that support variable opacity. It should be an integer
between 0 and 100, where 0 means completely transparent and 100 means
completely opaque. It can also have a nil value, which tells
Emacs not to set the frame opacity (leaving it to the window manager).
To prevent the frame from disappearing completely from view, the
variable frame-alpha-lower-limit defines a lower opacity limit.
If the value of the frame parameter is less than the value of this
variable, Emacs uses the latter. By default,
frame-alpha-lower-limit is 20.
The alpha frame parameter can also be a cons cell
(active . inactive), where active is the
opacity of the frame when it is selected, and inactive is the
opacity when it is not selected.
Some window systems do not support the alpha parameter for child
frames (see Child Frames).
alpha-background ¶Sets the background transparency of the frame. Unlike the alpha
frame parameter, this only controls the transparency of the background
while keeping foreground elements such as text fully opaque. It
should be an integer between 0 and 100, where 0 means
completely transparent and 100 means completely opaque (default).
The following frame parameters are semi-obsolete in that they are automatically equivalent to particular face attributes of particular faces (see Standard Faces in The Emacs Manual):
font ¶The name of the font for displaying text in the frame. This is a
string, either a valid font name for your system or the name of an Emacs
fontset (see Fontsets). It is equivalent to the font
attribute of the default face.
foreground-color ¶The color to use for characters. It is equivalent to
the :foreground attribute of the default face.
background-color ¶The color to use for the background of characters. It is equivalent to
the :background attribute of the default face.
mouse-color ¶The color for the mouse pointer. It is equivalent to the :background
attribute of the mouse face.
cursor-color ¶The color for the cursor that shows point. It is equivalent to the
:background attribute of the cursor face.
border-color ¶The color for the border of the frame. It is equivalent to the
:background attribute of the border face.
scroll-bar-foreground ¶If non-nil, the color for the foreground of scroll bars. It is
equivalent to the :foreground attribute of the
scroll-bar face.
scroll-bar-background ¶If non-nil, the color for the background of scroll bars. It is
equivalent to the :background attribute of the
scroll-bar face.
Here’s how to examine the data in an X-style window geometry specification:
The function x-parse-geometry converts a standard X window
geometry string to an alist that you can use as part of the argument to
make-frame.
The alist describes which parameters were specified in geom, and
gives the values specified for them. Each element looks like
(parameter . value). The possible parameter
values are left, top, width, and height.
For the size parameters, the value must be an integer. The position
parameter names left and top are not totally accurate,
because some values indicate the position of the right or bottom edges
instead. The value possibilities for the position parameters are:
an integer, a list (+ pos), or a list (- pos);
as previously described (see Position Parameters).
Here is an example:
(x-parse-geometry "35x70+0-0")
⇒ ((height . 70) (width . 35)
(top - 0) (left . 0))
Each terminal has a list of associated parameters. These terminal parameters are mostly a convenient way of storage for terminal-local variables, but some terminal parameters have a special meaning.
This section describes functions to read and change the parameter values
of a terminal. They all accept as their argument either a terminal or
a frame; the latter means use that frame’s terminal. An argument of
nil means the selected frame’s terminal.
This function returns an alist listing all the parameters of terminal and their values.
This function returns the value of the parameter parameter (a
symbol) of terminal. If terminal has no setting for
parameter, this function returns nil.
This function sets the parameter parameter of terminal to the specified value, and returns the previous value of that parameter.
Here’s a list of a few terminal parameters that have a special meaning:
background-modeThe classification of the terminal’s background color, either
light or dark.
normal-erase-is-backspaceValue is either 1 or 0, depending on whether
normal-erase-is-backspace-mode is turned on or off on this
terminal. See DEL Does Not Delete in The Emacs Manual.
terminal-inittedAfter the terminal is initialized, this is set to the terminal-specific initialization function.
tty-mode-set-stringsWhen present, a list of strings containing escape sequences that Emacs
will output while configuring a tty for rendering. Emacs emits these
strings only when configuring a terminal: if you want to enable a mode
on a terminal that is already active (for example, while in
tty-setup-hook), explicitly output the necessary escape
sequence using send-string-to-terminal in addition to adding
the sequence to tty-mode-set-strings.
tty-mode-reset-stringsWhen present, a list of strings that undo the effects of the strings
in tty-mode-set-strings. Emacs emits these strings when
exiting, deleting a terminal, or suspending itself.
Every frame has a name parameter; this serves as the default
for the frame title which window systems typically display at the top of
the frame. You can specify a name explicitly by setting the name
frame property.
Normally you don’t specify the name explicitly, and Emacs computes the
frame name automatically based on a template stored in the variable
frame-title-format. Emacs recomputes the name each time the
frame is redisplayed.
This variable specifies how to compute a name for a frame when you
have not explicitly specified one (via the frame’s parameters;
see Basic Parameters). The variable’s value is actually a mode
line construct, just like mode-line-format, except that the
‘%c’, ‘%C’, and ‘%l’ constructs are ignored.
See 模式行的数据结构.
This variable specifies how to compute the name for an iconified frame
when you have not explicitly specified the frame’s name via the
frame’s parameters. The resulting title appears in the frame’s icon
itself. If the value is a string, is should be a mode line construct
like that of frame-title-format. The value can also be
t, which means to use frame-title-format instead; this
avoids problems with some window managers and desktop environments,
where a change in a frame’s title (when a frame is iconified) is
interpreted as a request to raise the frame and/or give it input
focus. It is also useful if you want the frame’s title to be the same
no matter if the frame is iconified or not. The default value is a
string identical to the default value of frame-title-format.
This variable is set automatically by Emacs. Its value is t when
there are two or more frames (not counting minibuffer-only frames or
invisible frames). The default value of frame-title-format uses
multiple-frames so as to put the buffer name in the frame title
only when there is more than one frame.
The value of this variable is not guaranteed to be accurate except
while processing frame-title-format or
icon-title-format.
A live frame is one that has not been deleted. When a frame is deleted, it is removed from its terminal display, although it may continue to exist as a Lisp object until there are no more references to it.
This function deletes the frame frame. The argument frame must specify a live frame (see below) and defaults to the selected frame.
It first deletes any child frame of frame (see Child Frames)
and any frame whose delete-before frame parameter (see Frame Interaction Parameters) specifies frame. All such deletions are
performed recursively; so this step makes sure that no other frames with
frame as their ancestor will exist. Then, unless frame
specifies a tooltip, this function runs the hook
delete-frame-functions (each function getting one argument,
frame) before actually killing the frame. After actually killing
the frame and removing the frame from the frame list, delete-frame
runs after-delete-frame-functions.
Note that a frame cannot be deleted as long as its minibuffer serves as
surrogate minibuffer for another frame (see Minibuffers and Frames).
Normally, you cannot delete a frame if all other frames are invisible,
but if force is non-nil, then you are allowed to do so.
This function returns non-nil if the frame frame has not
been deleted. The possible non-nil return values are like those
of framep. See Frames.
Some window managers provide a command to delete a window. These work
by sending a special message to the program that operates the window.
When Emacs gets one of these commands, it generates a
delete-frame event, whose normal definition is a command that
calls the function delete-frame. See 其他系统事件.
This command deletes all frames on frame’s terminal, except
frame. If frame uses another frame’s minibuffer, that
minibuffer frame is left untouched. The argument frame must
specify a live frame and defaults to the selected frame. Internally,
this command works by calling delete-frame with force
nil for all frames that shall be deleted.
This function does not delete any of frame’s child frames (see Child Frames). If frame is a child frame, it deletes frame’s siblings only.
With the prefix argument iconify, the frames are iconified rather than deleted.
This function returns a list of all the live frames, i.e., those that
have not been deleted. It is analogous to buffer-list for
buffers, and includes frames on all terminals. The list that you get
is newly created, so modifying the list doesn’t have any effect on the
internals of Emacs.
This function returns a list of just the currently visible frames. See Visibility of Frames. Frames on text terminals always count as visible, even though only the selected one is actually displayed.
This function returns a list of Emacs’s frames, in Z (stacking) order
(see Raising, Lowering and Restacking Frames). The optional argument display
specifies which display to poll. display should be either a frame
or a display name (a string). If omitted or nil, that stands for
the selected frame’s display. It returns nil if display
contains no Emacs frame.
Frames are listed from topmost (first) to bottommost (last). As a
special case, if display is non-nil and specifies a live
frame, it returns the child frames of that frame in Z (stacking) order.
This function is not meaningful on text terminals.
This function lets you cycle conveniently through all the frames on a
specific terminal from an arbitrary starting point. It returns the
frame following frame, in the list of all live frames, on
frame’s terminal. The argument frame must specify a live
frame and defaults to the selected frame. It never returns a frame
whose no-other-frame parameter (see Frame Interaction Parameters) is non-nil.
The second argument, minibuf, says which frames to consider when deciding what the next frame should be:
nilConsider all frames except minibuffer-only frames.
visibleConsider only visible frames.
Consider only visible or iconified frames.
Consider only the frames using that particular window as their minibuffer window.
Consider all frames.
Like next-frame, but cycles through all frames in the opposite
direction.
See also next-window and previous-window, in Cyclic Ordering of Windows.
Some Lisp programs need to find one or more frames that satisfy a
given criteria. The function filtered-frame-list is provided for
this purpose.
This function returns the list of all the live frames which satisfy the
specified predicate. The argument predicate must be a
function of one argument, a frame to be tested against the filtering
criteria, and should return non-nil if the frame satisfies the
criteria.
Normally, each frame has its own minibuffer window at the bottom, which
is used whenever that frame is selected. You can get that window with
the function minibuffer-window (see Minibuffer 窗口).
However, you can also create a frame without a minibuffer. Such a frame
must use the minibuffer window of some other frame. That other frame
will serve as surrogate minibuffer frame for this frame and cannot
be deleted via delete-frame (see Deleting Frames) as long as
this frame is live.
When you create the frame, you can explicitly specify its minibuffer
window (in some other frame) with the minibuffer frame parameter
(see Buffer Parameters). If you don’t, then the minibuffer is found
in the frame which is the value of the variable
default-minibuffer-frame. Its value should be a frame that does
have a minibuffer.
If you use a minibuffer-only frame, you might want that frame to raise
when you enter the minibuffer. If so, set the variable
minibuffer-auto-raise to t. See Raising, Lowering and Restacking Frames.
This variable specifies the frame to use for the minibuffer window, by default. It does not affect existing frames. It is always local to the current terminal and cannot be buffer-local. See Multiple Terminals.
At any time, one frame in Emacs is the selected frame. The selected window (see Selecting Windows) always resides on the selected frame.
When Emacs displays its frames on several terminals (see Multiple Terminals), each terminal has its own selected frame. But only one of these is the selected frame: it’s the frame that belongs to the terminal from which the most recent input came. That is, when Emacs runs a command that came from a certain terminal, the selected frame is the one of that terminal. Since Emacs runs only a single command at any given time, it needs to consider only one selected frame at a time; this frame is what we call the selected frame in this manual. The display on which the selected frame is shown is the selected frame’s display.
This function returns the selected frame.
Some window systems and window managers direct keyboard input to the
window object that the mouse is in; others require explicit clicks or
commands to shift the focus to various window objects. Either
way, Emacs automatically keeps track of which frames have focus. To
explicitly switch to a different frame from a Lisp function, call
select-frame-set-input-focus.
The plural “frames” in the previous paragraph is deliberate: while Emacs itself has only one selected frame, Emacs can have frames on many different terminals (recall that a connection to a window system counts as a terminal), and each terminal has its own idea of which frame has input focus. Under the X Window System, where user input is organized into individual “seats” of input, each seat in turn can have its own specific input focus. When you set the input focus to a frame, you set the focus for that frame’s terminal on the last seat which interacted with Emacs, but frames on other terminals and seats may still remain focused.
If the input focus is set before any user interaction has occurred on the specified terminal, then the X server picks a random seat (normally the one with the lowest number) and sets the input focus there.
Lisp programs can switch frames temporarily by calling the function
select-frame. This does not alter the window system’s concept
of focus; rather, it escapes from the window manager’s control until
that control is somehow reasserted.
When using a text terminal, only one frame can be displayed at a time
on the terminal, so after a call to select-frame, the next
redisplay actually displays the newly selected frame. This frame
remains selected until a subsequent call to select-frame. Each
frame on a text terminal has a number which appears in the mode line
before the buffer name (see 模式行中使用的变量).
This function selects frame, raises it (should it happen to be
obscured by other frames) and tries to give it the window system’s
focus. On a text terminal, the next redisplay displays the new frame
on the entire terminal screen. The optional argument norecord
has the same meaning as for select-frame (see below).
The return value of this function is not significant.
Ideally, the function described next should focus a frame without also raising it above other frames. Unfortunately, many window-systems or window managers may refuse to comply.
This function gives frame the focus of the X server without
necessarily raising it. frame nil means use the selected
frame. Under X, the optional argument noactivate, if
non-nil, means to avoid making frame’s window-system window
the “active” window which should insist a bit more on avoiding to
raise frame above other frames.
On MS-Windows the noactivate argument has no effect. However, if frame is a child frame (see Child Frames), this function usually focuses frame without raising it above other child frames.
If there is no window system support, this function does nothing.
This function selects frame frame, temporarily disregarding the focus of the X server if any. The selection of frame lasts until the next time the user does something to select a different frame, or until the next time this function is called. (If you are using a window system, the previously selected frame may be restored as the selected frame after return to the command loop, because it still may have the window system’s input focus.)
The specified frame becomes the selected frame, and its terminal
becomes the selected terminal. This function then calls
select-window as a subroutine, passing the window selected
within frame as its first argument and norecord as its
second argument (hence, if norecord is non-nil, this
avoids changing the order of recently selected windows and the buffer
list). See Selecting Windows.
This function returns frame, or nil if frame has
been deleted.
In general, you should never use select-frame in a way that
could switch to a different terminal without switching back when
you’re done.
Emacs cooperates with the window system by arranging to select frames
as the server and window manager request. When a window system
informs Emacs that one of its frames has been selected, Emacs
internally generates a focus-in event. When an Emacs frame is
displayed on a text-terminal emulator, such as xterm, which
supports reporting of focus-change notification, the focus-in and
focus-out events are available even for text-mode frames. Focus
events are normally handled by handle-focus-in.
This function handles focus-in events from window systems and
terminals that support explicit focus notifications. It updates the
per-frame focus flags that frame-focus-state queries and calls
after-focus-change-function. In addition, it generates a
switch-frame event in order to switch the Emacs notion of the
selected frame to the frame most recently focused in some terminal.
It’s important to note that this switching of the Emacs selected frame
to the most recently focused frame does not mean that other frames do
not continue to have the focus in their respective terminals. Do not
invoke this function yourself: instead, attach logic to
after-focus-change-function.
This function handles a switch-frame event, which Emacs generates for itself upon focus notification or under various other circumstances involving an input event arriving at a different frame from the last event. Do not invoke this function yourself.
This function redirects focus from frame to focus-frame.
This means that focus-frame will receive subsequent keystrokes and
events intended for frame. After such an event, the value of
last-event-frame will be focus-frame. Also, switch-frame
events specifying frame will instead select focus-frame.
If focus-frame is omitted or nil, that cancels any existing
redirection for frame, which therefore once again receives its own
events.
One use of focus redirection is for frames that don’t have minibuffers. These frames use minibuffers on other frames. Activating a minibuffer on another frame redirects focus to that frame. This puts the focus on the minibuffer’s frame, where it belongs, even though the mouse remains in the frame that activated the minibuffer.
Selecting a frame can also change focus redirections. Selecting frame
bar, when foo had been selected, changes any redirections
pointing to foo so that they point to bar instead. This
allows focus redirection to work properly when the user switches from
one frame to another using select-window.
This means that a frame whose focus is redirected to itself is treated
differently from a frame whose focus is not redirected.
select-frame affects the former but not the latter.
The redirection lasts until redirect-frame-focus is called to
change it.
This function retrieves the last known focus state of frame.
It returns nil if the frame is known not to be focused,
t if the frame is known to be focused, or unknown if
Emacs does not know the focus state of the frame. (You may see this
last state in TTY frames running on terminals that do not support
explicit focus notifications.)
This function is called with no arguments when Emacs notices that a frame may have gotten or lost focus. Focus events are delivered asynchronously, and may not be delivered in the expected order, so code that wants to do something depending on the state of focused frames have go through all the frames and check.
For instance, here’s a simple example function that sets the background color based on whether the frame has focus or not:
(add-function :after after-focus-change-function
#'my-change-background)
(defun my-change-background ()
(dolist (frame (frame-list))
(pcase (frame-focus-state frame)
(`t (set-face-background 'default "black" frame))
(`nil (set-face-background 'default "#404040" frame)))))
Multiple frames may appear to have input focus simultaneously due to focus event delivery differences, the presence of multiple Emacs terminals, and other factors, and code should be robust in the face of this situation.
Depending on window system, focus events may also be delivered repeatedly and with different focus states before settling to the expected values. Code relying on focus notifications should “debounce” any user-visible updates arising from focus changes, perhaps by deferring work until redisplay.
This function may be called in arbitrary contexts, including from
inside read-event, so take the same care as you might when
writing a process filter.
This option informs Emacs whether and how the window manager transfers focus when you move the mouse pointer into a frame. It can have three meaningful values:
nilThe default value nil should be used when your window manager
follows a “click-to-focus” policy where you have to click the mouse
inside of a frame in order for that frame to gain focus.
tThe value t should be used when your window manager has the focus
automatically follow the position of the mouse pointer but a frame that
gains focus is not raised automatically and may even remain occluded by
other window-system windows.
auto-raiseThe value auto-raise should be used when your window manager has
the focus automatically follow the position of the mouse pointer and a
frame that gains focus is raised automatically.
If this option is non-nil, Emacs moves the mouse pointer to the
frame selected by select-frame-set-input-focus. That function is
used by a number of commands like, for example, other-frame and
pop-to-buffer.
The distinction between the values t and auto-raise is not
needed for “normal” frames because the window manager usually takes
care of raising them. It is useful to automatically raise child frames
via mouse-autoselect-window (see Mouse Window Auto-selection).
Note that this option does not distinguish “sloppy” focus (where the frame that previously had focus retains focus as long as the mouse pointer does not move into another window-system window) from “strict” focus (where a frame immediately loses focus when it’s left by the mouse pointer). Neither does it recognize whether your window manager supports delayed focusing or auto-raising where you can explicitly specify the time until a new frame gets focus or is auto-raised.
You can supply a “focus follows mouse” policy for individual Emacs
windows by customizing the variable mouse-autoselect-window
(see Mouse Window Auto-selection).
A frame on a graphical display may be visible, invisible, or iconified. If it is visible, its contents are displayed in the usual manner. If it is iconified, its contents are not displayed, but there is a little icon somewhere to bring the frame back into view (some window managers refer to this state as minimized rather than iconified, but from Emacs’s point of view they are the same thing). If a frame is invisible, it is not displayed at all.
The concept of visibility is strongly related to that of (un-)mapped
frames. A frame (or, more precisely, its window-system window) is and
becomes mapped when it is displayed for the first time and
whenever it changes its state of visibility from iconified or
invisible to visible. Conversely, a frame is and becomes
unmapped whenever it changes its status from visible to
iconified or invisible.
Visibility is meaningless on text terminals, since only the selected frame is actually displayed in any case.
This function returns the visibility status of frame frame. The
value is t if frame is visible, nil if it is
invisible, and icon if it is iconified.
On a text terminal, all frames are considered visible for the purposes of this function, even though only one frame is displayed. See Raising, Lowering and Restacking Frames.
This function iconifies frame frame. If you omit frame, it iconifies the selected frame. This usually makes all child frames of frame (and their descendants) invisible (see Child Frames).
This function makes frame frame visible. If you omit frame,
it makes the selected frame visible. This does not raise the frame, but
you can do that with raise-frame if you wish (see Raising, Lowering and Restacking Frames).
Making a frame visible usually makes all its child frames (and their descendants) visible as well (see Child Frames).
This function makes frame frame invisible. If you omit frame, it makes the selected frame invisible. Usually, this makes all child frames of frame (and their descendants) invisible too (see Child Frames).
Unless force is non-nil, this function refuses to make
frame invisible if all other frames are invisible.
The visibility status of a frame is also available as a frame parameter. You can read or change it as such. See Window Management Parameters. The user can also iconify and deiconify frames with the window manager. This happens below the level at which Emacs can exert any control, but Emacs does provide events that you can use to keep track of such changes. See 其他系统事件.
This function returns non-nil if frame is currently
being rendered with double buffering. frame defaults to the
selected frame.
Most window systems use a desktop metaphor. Part of this metaphor is the idea that system-level windows (representing, e.g., Emacs frames) are stacked in a notional third dimension perpendicular to the screen surface. The order induced by stacking is total and usually referred to as stacking (or Z-) order. Where the areas of two windows overlap, the one higher up in that order will (partially) cover the one underneath.
You can raise a frame to the top of that order or lower a
frame to its bottom by using the functions raise-frame and
lower-frame. You can restack a frame directly above or
below another frame using the function frame-restack.
Note that all functions described below will respect the adherence of
frames (and all other window-system windows) to their respective z-group
(see Position Parameters). For example, you usually cannot lower a
frame below that of the desktop window and you cannot raise a frame
whose z-group parameter is nil above the window-system’s
taskbar or tooltip window.
This function raises frame frame (default, the selected frame) above all other frames belonging to the same or a lower z-group as frame. If frame is invisible or iconified, this makes it visible. If frame is a child frame (see Child Frames), this raises frame above all other child frames of its parent.
This function lowers frame frame (default, the selected frame) below all other frames belonging to the same or a higher z-group as frame. If frame is a child frame (see Child Frames), this lowers frame below all other child frames of its parent.
This function restacks frame1 below frame2. This implies
that if both frames are visible and their display areas overlap,
frame2 will (partially) obscure frame1. If the optional
third argument above is non-nil, this function restacks
frame1 above frame2. This means that if both frames are
visible and their display areas overlap, frame1 will (partially)
obscure frame2.
Technically, this function may be thought of as an atomic action performed in two steps: The first step removes frame1’s window-system window from the display. The second step reinserts frame1’s window into the display below (above if above is true) that of frame2. Hence the position of frame2 in its display’s Z (stacking) order relative to all other frames excluding frame1 remains unaltered.
Some window managers may refuse to restack windows.
Note that the effect of restacking will only hold as long as neither of
the involved frames is iconified or made invisible. You can use the
z-group (see Position Parameters) frame parameter to add a
frame to a group of frames permanently shown above or below other
frames. As long as a frame belongs to one of these groups, restacking
it will only affect its relative stacking position within that group.
The effect of restacking frames belonging to different z-groups is
undefined. You can list frames in their current stacking order with the
function frame-list-z-order (see Finding All Frames).
If this is non-nil, activation of the minibuffer raises the frame
that the minibuffer window is in.
On window systems, you can also enable auto-raising (on frame selection) or auto-lowering (on frame deselection) using frame parameters. See Window Management Parameters.
The concept of raising and lowering frames also applies to text terminal frames. On each text terminal, only the top frame is displayed at any one time.
This function returns the top frame on terminal. terminal
should be a terminal object, a frame (meaning that frame’s terminal),
or nil (meaning the selected frame’s terminal). If it does not
refer to a text terminal, the return value is nil.
A frame configuration records the current arrangement of frames, all their properties, and the window configuration of each one. (See Window Configurations.)
This function returns a frame configuration list that describes the current arrangement of frames and their contents.
This function restores the state of frames described in configuration. However, this function does not restore deleted frames.
Ordinarily, this function deletes all existing frames not listed in
configuration. But if nodelete is non-nil, the
unwanted frames are iconified instead.
Child frames are objects halfway between windows (see Windows) and “normal” frames. Like windows, they are attached to an owning frame. Unlike windows, they may overlap each other—changing the size or position of one child frame does not change the size or position of any of its sibling child frames.
By design, operations to make or modify child frames are implemented with the help of frame parameters (see Frame Parameters) without any specialized functions or customizable variables. Note that child frames are meaningful on graphical terminals only.
To create a new child frame or to convert a normal frame into a child
frame, set that frame’s parent-frame parameter (see Frame Interaction Parameters) to that of an already existing frame. The
frame specified by that parameter will then be the frame’s parent frame
as long as the parameter is not changed or reset. Technically, this
makes the child frame’s window-system window a child window of the
parent frame’s window-system window.
The parent-frame parameter can be changed at any time.
Setting it to another frame reparents the child frame. Setting
it to another child frame makes the frame a nested child frame.
Setting it to nil restores the frame’s status as a top-level
frame—a frame whose window-system window is a child of its display’s
root window.23
Since child frames can be arbitrarily nested, a frame can be both a child and a parent frame. Also, the relative roles of child and parent frame may be reversed at any time (though it’s usually a good idea to keep the size of a child frame sufficiently smaller than that of its parent). An error will be signaled for the attempt to make a frame an ancestor of itself.
Most window-systems clip a child frame at the native edges
(see Frame Geometry) of its parent frame—everything outside these
edges is usually invisible. A child frame’s left and top
parameters specify a position relative to the top-left corner of its
parent’s native frame. When the parent frame is resized, this position
remains conceptually unaltered.
NS builds do not clip child frames at the parent frame’s edges, allowing them to be positioned so they do not obscure the parent frame while still being visible themselves.
Usually, moving a parent frame moves along all its child frames and
their descendants as well, keeping their relative positions unaltered.
Note that the hook move-frame-functions (see Frame Position)
is run for a child frame only when the position of the child frame
relative to its parent frame changes.
When a parent frame is resized, its child frames conceptually retain
their previous sizes and their positions relative to the left upper
corner of the parent. This means that a child frame may become
(partially) invisible when its parent frame shrinks. The parameter
keep-ratio (see Frame Interaction Parameters) can be used to
resize and reposition a child frame proportionally whenever its parent
frame is resized. This may avoid obscuring parts of a frame when its
parent frame is shrunk.
A visible child frame always appears on top of its parent frame thus obscuring parts of it, except on NS builds where it may be positioned beneath the parent. This is comparable to the window-system window of a top-level frame which also always appears on top of its parent window—the desktop’s root window. When a parent frame is iconified or made invisible (see Visibility of Frames), its child frames are made invisible. When a parent frame is deiconified or made visible, its child frames are made visible.
When a parent frame is about to be deleted (see Deleting Frames), its child frames are recursively deleted before it. There is one exception to this rule: When the child frame serves as a surrogate minibuffer frame (see Minibuffers and Frames) for another frame, it is retained until the parent frame has been deleted. If, at this time, no remaining frame uses the child frame as its minibuffer frame, Emacs will try to delete the child frame too. If that deletion fails for whatever reason, the child frame is made a top-level frame.
Whether a child frame can have a menu or tool bar is window-system or window manager dependent. Most window-systems explicitly disallow menu bars for child frames. It seems advisable to disable both, menu and tool bars, via the frame’s initial parameters settings.
Usually, child frames do not exhibit window manager decorations like a title bar or external borders (see Frame Geometry). When the child frame does not show a menu or tool bar, any other of the frame’s borders (see Layout Parameters) can be used instead of the external borders.
In particular, under X (but not when building with GTK+), the frame’s
outer border can be used. On MS-Windows, specifying a non-zero outer
border width will show a one-pixel wide external border. Under all
window-systems, the internal border can be used. In either case, it’s
advisable to disable a child frame’s window manager decorations with the
undecorated frame parameter (see Window Management Parameters).
To resize or move an undecorated child frame with the mouse, special
frame parameters (see Mouse Dragging Parameters) have to be used.
The internal border of a child frame, if present, can be used to resize
the frame with the mouse, provided that frame has a non-nil
drag-internal-border parameter. If set, the snap-width
parameter indicates the number of pixels where the frame snaps at
the respective edge or corner of its parent frame.
There are two ways to drag an entire child frame with the mouse: The
drag-with-mode-line parameter, if non-nil, enables
dragging a frame without minibuffer window (see Minibuffer 窗口) via the mode line area of its bottommost window. The
drag-with-header-line parameter, if non-nil, enables
dragging the frame via the header line area of its topmost window.
In order to give a child frame a draggable header or mode line, the
window parameters mode-line-format and header-line-format
are handy (see Window Parameters). These allow removing an
unwanted mode line (when drag-with-header-line is chosen) and to
remove mouse-sensitive areas which might interfere with frame dragging.
When the user drags a frame with a mouse and overshoots, it’s easy
to drag a frame out of the screen area of its parent. Retrieving such
a frame can be hairy once the mouse button has been released. To
prevent such a situation, it is advisable to set the frame’s
top-visible or bottom-visible parameter (see Mouse Dragging Parameters).
Set the top-visible parameter of a child frame to a number
when you intend to allow the user dragging that frame by its header
line. Setting top-visible to a number inhibits dragging the
top edge of the child frame above the top edge of its parent. Set the
bottom-visible parameter to a number when you intend to drag
that frame via its mode line; this inhibits dragging the bottom edge
of the child frame beneath the bottom edge of its parent. In either
case, that number also specifies width and height (in pixels) of the
area of the child frame that remains visible during dragging.
When a child frame is used for displaying a buffer via
display-buffer-in-child-frame (see Action Functions for Buffer Display), the frame’s auto-hide-function parameter
(see Frame Interaction Parameters) can be set to a function, in
order to appropriately deal with the frame when the window displaying
the buffer shall be quit.
When a child frame is used during minibuffer interaction, for example,
to display completions in a separate window, the minibuffer-exit
parameter (see Frame Interaction Parameters) is useful in order to
deal with the frame when the minibuffer is exited.
The behavior of child frames deviates from that of top-level frames in a number of other ways as well. Here we sketch a few of them:
iconify-frame on a child frame will try to iconify the top-level
frame corresponding to that child frame instead. To obtain a different
behavior, users may customize the option iconify-child-frame
described below.
z-group (see Position Parameters)
of a child frame changes only the stacking order of child frames with
the same parent.
mouse-autoselect-window can
help in this regard (see Mouse Window Auto-selection).
The following two functions can be useful when working with child and parent frames:
This function returns the parent frame of frame. The parent frame of frame is the Emacs frame whose window-system window is the parent window of frame’s window-system window. If such a frame exists, frame is considered a child frame of that frame.
This function returns nil if frame has no parent frame.
This functions returns non-nil if ancestor is an ancestor
of descendant. ancestor is an ancestor of descendant
when it is either descendant’s parent frame or it is an ancestor
of descendant’s parent frame. Both, ancestor and
descendant must specify live frames.
Note also the function window-largest-empty-rectangle
(see Coordinates and Windows) which can be used to inscribe a child
frame in the largest empty area of an existing window. This can be
useful to avoid that a child frame obscures any text shown in that
window.
Customizing the following option can be useful to tweak the behavior of
iconify-frame for child frames.
This option tells Emacs how to proceed when it is asked to iconify a
child frame. If it is nil, iconify-frame will do nothing
when invoked on a child frame. If it is iconify-top-level, Emacs
will try to iconify the top-level frame that is the ancestor of this
child frame instead. If it is make-invisible, Emacs will try to
make this child frame invisible instead of iconifying it.
Any other value means to try iconifying the child frame. Since such an attempt may not be honored by all window managers and can even lead to making the child frame unresponsive to user actions, the default is to iconify the top level frame instead.
Sometimes it is useful to track the mouse, which means to display something to indicate where the mouse is and move the indicator as the mouse moves. For efficient mouse tracking, you need a way to wait until the mouse actually moves.
The convenient way to track the mouse is to ask for events to represent mouse motion. Then you can wait for motion by waiting for an event. In addition, you can easily handle any other sorts of events that may occur. That is useful, because normally you don’t want to track the mouse forever—only until some other event, such as the release of a button.
This macro executes body, with generation of mouse motion events
enabled. Typically, body would use read-event to read
the motion events and modify the display accordingly. See 移动事件, for the format of mouse motion events.
The value of track-mouse is that of the last form in
body. You should design body to return when it sees the
up-event that indicates the release of the button, or whatever kind of
event means it is time to stop tracking. Its value also controls how
mouse events are reported while a mouse button is held down: if it is
dropping or drag-source, the motion events are reported
relative to the frame underneath the pointer. If there is no such
frame, the events will be reported relative to the frame the mouse
buttons were first pressed on. In addition, the posn-window of
the mouse position list will be nil if the value is
drag-source. This is useful to determine if a frame is not
directly visible underneath the mouse pointer.
The track-mouse macro causes Emacs to generate mouse motion
events by binding the variable track-mouse to a
non-nil value. If that variable has the special value
dragging, it additionally instructs the display engine to
refrain from changing the shape of the mouse pointer. This is
desirable in Lisp programs that require mouse dragging across large
portions of Emacs display, which might otherwise cause the mouse
pointer to change its shape according to the display portion it hovers
on (see Pointer Shape). Therefore, Lisp programs that need the
mouse pointer to retain its original shape during dragging should bind
track-mouse to the value dragging at the beginning of
their body.
The usual purpose of tracking mouse motion is to indicate on the screen the consequences of pushing or releasing a button at the current position.
In many cases, you can avoid the need to track the mouse by using
the mouse-face text property (see Properties with Special Meanings).
That works at a much lower level and runs more smoothly than
Lisp-level mouse tracking.
The functions mouse-position and set-mouse-position
give access to the current position of the mouse.
This function returns a description of the position of the mouse. The
value looks like (frame x . y), where x
and y are integers giving the (possibly rounded) position in
multiples of the default character size of frame (see Frame Font) relative to the native position of frame (see Frame Geometry).
If non-nil, the value of this variable is a function for
mouse-position to call. mouse-position calls this
function just before returning, with its normal return value as the
sole argument, and it returns whatever this function returns to it.
This abnormal hook exists for the benefit of packages like xt-mouse.el that need to do mouse handling at the Lisp level.
If non-nil, TTY menus will call mouse-position-function
as described above. This exists for cases where
mouse-position-function is not safe to be called by the TTY
menus, such as if it could trigger redisplay.
This function warps the mouse to position x, y in frame frame. The arguments x and y are integers, giving the position in multiples of the default character size of frame (see Frame Font) relative to the native position of frame (see Frame Geometry).
The resulting mouse position is constrained to the native frame of frame. If frame is not visible, this function does nothing. The return value is not significant.
This function is like mouse-position except that it returns
coordinates in units of pixels rather than units of characters.
This function warps the mouse like set-mouse-position except that
x and y are in units of pixels rather than units of
characters.
The resulting mouse position is not constrained to the native frame of frame. If frame is not visible, this function does nothing. The return value is not significant.
On a graphical terminal the following two functions allow the absolute position of the mouse cursor to be retrieved and set.
This function returns a cons cell (x . y) of the coordinates of the mouse cursor position in pixels, relative to a position (0, 0) of the selected frame’s display.
This function moves the mouse cursor to the position (x, y). The coordinates x and y are interpreted in pixels relative to a position (0, 0) of the selected frame’s display.
The following function can tell whether the mouse cursor is currently visible on a frame:
This predicate function returns non-nil if the mouse pointer
displayed on frame is visible; otherwise it returns nil.
frame omitted or nil means the selected frame. This is
useful when make-pointer-invisible is set to t: it
allows you to know if the pointer has been hidden.
See Mouse Avoidance in The Emacs Manual.
A Lisp program can pop up a menu so that the user can choose an alternative with the mouse. On a text terminal, if the mouse is not available, the user can choose an alternative using the keyboard motion keys—C-n, C-p, or up- and down-arrow keys.
This function displays a pop-up menu and returns an indication of what selection the user makes.
The argument position specifies where on the screen to put the
top left corner of the menu. It can be either a mouse button or
touchscreen-begin event (which says to put the menu where the
user actuated the button) or a list of this form:
((xoffset yoffset) window)
where xoffset and yoffset are coordinates, measured in pixels, counting from the top left corner of window. window may be a window or a frame.
If position is t, it means to use the current mouse
position (or the top-left corner of the frame if the mouse is not
available on a text terminal). If position is nil, it
means to precompute the key binding equivalents for the keymaps
specified in menu, without actually displaying or popping up the
menu.
The argument menu says what to display in the menu. It can be a
keymap or a list of keymaps (see 菜单按键映射). In this case, the
return value is the list of events corresponding to the user’s choice.
This list has more than one element if the choice occurred in a
submenu. (Note that x-popup-menu does not actually execute the
command bound to that sequence of events.) On text terminals and
toolkits that support menu titles, the title is taken from the prompt
string of menu if menu is a keymap, or from the prompt
string of the first keymap in menu if it is a list of keymaps
(see 定义菜单).
Alternatively, menu can have the following form:
(title pane1 pane2...)
where each pane is a list of form
(title item1 item2...)
Each item should be a cons cell, (line . value),
where line is a string and value is the value to return if
that line is chosen. Unlike in a menu keymap, a nil
value does not make the menu item non-selectable.
Alternatively, each item can be a string rather than a cons
cell; this makes a non-selectable menu item.
If the user gets rid of the menu without making a valid choice, for
instance by clicking the mouse away from a valid choice or by typing
C-g, then this normally results in a quit and
x-popup-menu does not return. But if position is a mouse
button event (indicating that the user invoked the menu with the
mouse) then no quit occurs and x-popup-menu returns nil.
Usage note: Don’t use x-popup-menu to display a menu
if you could do the job with a prefix key defined with a menu keymap.
If you use a menu keymap to implement a menu, C-h c and C-h
a can see the individual items in that menu and provide help for them.
If instead you implement the menu by defining a command that calls
x-popup-menu, the help facilities cannot know what happens inside
that command, so they cannot give any help for the menu’s items.
The menu bar mechanism, which lets you switch between submenus by
moving the mouse, cannot look within the definition of a command to see
that it calls x-popup-menu. Therefore, if you try to implement a
submenu using x-popup-menu, it cannot work with the menu bar in
an integrated fashion. This is why all menu bar submenus are
implemented with menu keymaps within the parent menu, and never with
x-popup-menu. See 菜单栏.
If you want a menu bar submenu to have contents that vary, you should
still use a menu keymap to implement it. To make the contents vary, add
a hook function to menu-bar-update-hook to update the contents of
the menu keymap as necessary.
A normal hook run immediately before a pop-up menu is displayed,
either directly by calling x-popup-menu, or through a menu
keymap. It won’t be called if x-popup-menu returns for some
other reason without displaying a pop-up menu.
An on-screen keyboard is a special kind of pop up provided by the system, with rows of clickable buttons that act as a real keyboard.
On certain systems (see On-Screen Keyboards in The Emacs Manual), Emacs is supposed to display and hide the on screen keyboard depending on whether or not the user is about to type something.
This function displays or hides the on-screen keyboard on behalf of
the frame frame. If hide is non-nil, then the
on-screen keyboard is hidden; otherwise, it is displayed.
It returns whether or not the on screen keyboard may have been displayed, which should be used to determine whether or not to hide the on-screen keyboard later.
This has no effect if the system automatically detects when to display the on-screen keyboard, or when it does not provide any on-screen keyboard.
A dialog box is a variant of a pop-up menu—it looks a little
different, it always appears in the center of a frame, and it has just
one level and one or more buttons. The main use of dialog boxes is
for asking questions that the user can answer with “yes”, “no”,
and a few other alternatives. With a single button, they can also
force the user to acknowledge important information. The functions
y-or-n-p and yes-or-no-p use dialog boxes instead of the
keyboard, when called from commands invoked by mouse clicks.
This function displays a pop-up dialog box and returns an indication of what selection the user makes. The argument contents specifies the alternatives to offer; it has this format:
(title (string . value)...)
which looks like the list that specifies a single pane for
x-popup-menu.
The return value is value from the chosen alternative.
As for x-popup-menu, an element of the list may be just a
string instead of a cons cell (string . value).
That makes a box that cannot be selected.
If nil appears in the list, it separates the left-hand items from
the right-hand items; items that precede the nil appear on the
left, and items that follow the nil appear on the right. If you
don’t include a nil in the list, then approximately half the
items appear on each side.
Dialog boxes always appear in the center of a frame; the argument
position specifies which frame. The possible values are as in
x-popup-menu, but the precise coordinates or the individual
window don’t matter; only the frame matters.
If header is non-nil, the frame title for the box is
‘Information’, otherwise it is ‘Question’. The former is used
for message-box (see message-box). (On text terminals, the
box title is not displayed.)
In some configurations, Emacs cannot display a real dialog box; so instead it displays the same items in a pop-up menu in the center of the frame.
If the user gets rid of the dialog box without making a valid choice,
for instance using the window manager, then this produces a quit and
x-popup-dialog does not return.
You can specify the mouse pointer style for particular text or
images using the pointer text property, and for images with the
:pointer and :map image properties. The values you can
use in these properties are in the table below. The actual shapes
may vary between systems; the descriptions are examples.
textnilThe usual mouse pointer style used over text (an “I”-like shape).
arrowvdragmodelineAn arrow that points north-west.
handA hand that points upwards.
hdragA right-left arrow.
nhdragAn up-down arrow.
hourglassA rotating ring.
Over void parts of the window (parts that do not correspond to any
of the buffer contents), the mouse pointer usually uses the
arrow style, but you can specify a different style (one of
those above) by setting void-text-area-pointer.
This variable specifies the mouse pointer style for void text areas.
These include the areas after the end of a line or below the last line
in the buffer. The default is to use the arrow (non-text)
pointer style.
When using some window systems, you can specify what the text
pointer style really looks like by setting the variable
x-pointer-shape.
This variable specifies the pointer shape to use ordinarily in the
Emacs frame, for the text pointer style.
This variable specifies the pointer shape to use when the mouse is over mouse-sensitive text.
These variables affect newly created frames. They do not normally affect existing frames; however, if you set the mouse color of a frame, that also installs the current value of those two variables. See Font and Color Parameters.
The values you can use, to specify either of these pointer shapes, are defined in the file lisp/term/x-win.el. Use M-x apropos RET x-pointer RET to see a list of them.
In window systems, such as X, data can be transferred between different applications by means of selections. Each window system defines an arbitrary number of selection types, all storing their own data; however, only three are commonly used: the clipboard, primary selection, and secondary selection. See Cut and Paste in The GNU Emacs Manual, for Emacs commands that make use of these selections. This section documents the low-level functions for reading and setting window-system selections; See Accessing Selections, for documentation concerning selection types and data formats under particular window systems.
This function sets a window-system selection. It takes two arguments: a selection type type, and the value to assign to it, data.
type should be a symbol; it is usually one of PRIMARY,
SECONDARY or CLIPBOARD. These are generally symbols
with upper-case names, in accord with X Window System conventions. If
type is nil, that stands for PRIMARY.
If data is nil, it means to clear out the selection.
Otherwise, data may be a string, a symbol, an integer, an
overlay, or a cons of two markers pointing to the same buffer. An
overlay or a pair of markers stands for text in the overlay or between
the markers. The argument data may also be a vector of valid
non-vector selection values.
If data is a string, then its text properties can specify values
used for individual data types. For example, if data has a
property named text/uri-list, then a call to
gui-get-selection with the data type text/uri-list will
result in the value of that property being used instead of data
itself.
This function returns data.
This function accesses selections set up by Emacs or by other
programs. It takes two optional arguments, type and
data-type. The default for type, the selection type, is
PRIMARY.
The data-type argument specifies the form of data conversion to
use, to convert the raw data obtained from another program into Lisp
data. It defaults to STRING. See X Selections, for an
enumeration of data types valid on X, and see Other Selections for
those elsewhere. On X Window system, we recommend to always specify a
particular data-type, especially if the selection is expected to
be non-ASCII text (in which case Lisp programs should prefer
UTF8_STRING as the value of data-type). This is because
the default data-type value, STRING, can only support
Latin-1 text, which in many cases is nowadays inadequate.
This variable provides a coding system (see Coding Systems) which is used to encode selection data, and takes effect on MS-Windows and X. It is also used in the MS-DOS port when it runs on MS-Windows and can access the Windows clipboard text.
On X, the value of this variable provides the coding system which
gui-get-selection will use to decode selection data for a
subset of text data types, and also forces replies to selection
requests for the polymorphic TEXT data type to be encoded by
the compound-text-with-extensions coding system rather than
Unicode.
On MS-Windows, this variable is generally ignored, as the MS-Windows clipboard provides the information about decoding as part of the clipboard data, and uses either UTF-16 or locale-specific encoding automatically as appropriate. We recommend to set the value of this variable only on the older Windows 9X, as it is otherwise used only in the very rare cases when the information provided by the clipboard data is unusable for some reason.
The default value of this variable is the system code page under
MS-Windows 98 or Me, utf-16le-dos on Windows
NT/W2K/XP/Vista/7/8/10/11, iso-latin-1-dos on MS-DOS, and
nil elsewhere.
For backward compatibility, there are obsolete aliases
x-get-selection and x-set-selection, which were the
names of gui-get-selection and gui-set-selection before
Emacs 25.1.
The data types and selections that gui-get-selection and
gui-set-selection understand are not precisely specified and
differ subject to the window system on which Emacs is running.
At the same time, gui-set-selection abstracts over plenty of
complexity: its data argument is given verbatim to
system-specific code to be rendered suitable for transfer to the
window system or requesting clients.
The most comprehensive implementation of selections exists under the X Window System. This is both an artifact of history (X was the first window system supported by Emacs) and one occasioned by technical considerations: X selections are not merely an expedient for the transfer of text and multimedia content between clients, but a general inter-client communication system, a design that has yielded a proliferation of selection and data types.
Compounding this confusion, there is another inter-client communication mechanism under X: the Inter-Client Exchange. ICE is only used by Emacs to communicate with session managers, and is a separate topic.
X refrains from defining fixed data types for selection data or a fixed number of selections. Selections are identified by X “atoms”, which are unique 29-bit identifiers issued by the X server for string names. This complexity is hidden by Emacs: when Lisp provides a symbol whose name is that of the atom, Emacs will request these identifiers without further intervention.
When a program “sets” a selection under X, it actually makes itself the “owner” of the selection—the X server will then deliver selection requests to the program, which is obliged to respond to the requesting client with the selection data.
Similarly, a program does not “get” selection data from the X server. Instead, its selection requests are sent to the client with the window which last asserted ownership over the selection, which is expected to respond with the requested data.
Each selection request incorporates three parameters:
gui-get-selection.
The selection owner responds by transferring to the requestor a
series of bytes, 16 bit words, or 32 bit words, along with another
atom identifying the type of those words. After requesting a
selection, Emacs then applies its own interpretation of the data
format and data type to convert the data transferred by the selection
owner to a Lisp representation, which gui-get-selection
returns.
Emacs converts selection data consisting of any series of bytes to a unibyte string holding those bytes, that consisting of a single 16-bit or 32-bit word as an unsigned number, and that consisting of multiple such words as a vector of unsigned numbers. The exceptions to this general pattern are that Emacs applies special treatment for data from the following conversion targets:
INTEGER16-bit or 32-bit words of this type are treated as signed rather than unsigned integers. If there are multiple words in the selection data, a vector is returned; otherwise, the integer is returned by itself.
ATOM32-bit words of this type are treated as X atoms, and returned (either
alone or as vectors) as Lisp symbols by the names they identify.
Invalid atoms are replaced by nil.
COMPOUND_TEXTUTF8_STRINGSTRINGA single foreign-selection text property set to the type of the
selection data will be placed in unibyte strings derived from a
request for these data types.
Each selection owner must return at least two selection targets:
TARGETS, which returns a number of atoms describing the
selection targets that the owner supports, and MULTIPLE, used
for internal purposes by X clients. A selection owner may support any
number of other targets, some of which may be standardized by the X
Consortium’s
Inter-Client Communication Conventions Manual, while others, such as
UTF8_STRING, were meant to be standardized by the XFree86
Project, but their standardization was never completed.
Requests for a given selection target may, by convention, return data in a specific type, or it may return data in one of several types, whichever is most convenient for the selection owner; the latter type of selection target is dubbed a polymorphic target. In response to a request, a selection target may also return no data at all, whereafter the selection owner executes some action as a side effect. Targets that are thus replied to are termed side-effect targets.
Here are some selection targets whose behavior is generally
consistent with a standard when requested from the CLIPBOARD,
PRIMARY, or SECONDARY selections.
ADOBE_PORTABLE_DOCUMENT_FORMATThis target returns data in Adobe System’s “Portable Document Format” format, as a string.
APPLE_PICTThis target returns data in the “PICT” image format used on Macintosh computers, as a string.
BACKGROUNDBITMAPCOLORMAPFOREGROUNDTogether, these four targets return integer data necessary to make use of a bitmap image stored on the X server: the pixel value of the bitmap’s background color, the X identifier of the bitmap, the colormap inside which the background and foreground are allocated, and the pixel value of the bitmap’s foreground color.
CHARACTER_POSITIONThis target returns two unsigned 32-bit integers of type SPAN
describing the start and end positions of the selection data in the
text field containing it, in bytes.
COMPOUND_TEXTThis target returns a string of type COMPOUND_TEXT in the X
Consortium’s multi-byte text encoding system.
DELETEThis target returns nothing, but as a side-effect deletes the selection contents from any text field containing them.
DRAWABLEPIXMAPThis target returns a list of unsigned 32-bit integers, each of which corresponds to an X server drawable or pixmap.
ENCAPSULATED_POSTSCRIPT_ADOBE_EPSThis target returns a string containing encapsulated Postscript code.
FILE_NAMEThis target returns a string containing one or more file names, separated by NULL characters.
HOST_NAMEThis target returns a string containing the fully-qualified domain name of the machine on which the selection owner is running.
USERThis target returns a string containing the user name of the machine on which the selection owner is running.
LENGTHThis target returns an unsigned 32-bit or 16-bit integer containing the length of the selection data.
LINE_NUMBERThis target returns two unsigned 32-bit integers of type SPAN
describing the line numbers corresponding to the start and end
positions of the selection data in the text field containing it.
MODULEThis target returns the name of any function containing the selection data. It is principally requested by text editors.
STRINGThis target returns the selection data as a string of type
STRING, encoded in ISO Latin-1 format, with Unix newline
characters.
C_STRINGThis target returns the selection data as a “C string”. This has been interpreted as meaning the raw selection data in whatever encoding used by the owner, either terminated with a NULL byte or not at all, or an ASCII string which may or may not be terminated.
UTF8_STRINGThis returns the selection data as a string of type
UTF8_STRING, encoded in UTF-8, with unspecified EOL format.
TIMESTAMPThis target returns the X server time at which the selection owner
took ownership over the selection as a 16-bit or 32-bit word of type
CARDINAL.
TEXTThis polymorphic target returns selection data as a string, either
COMPOUND_TEXT, STRING, C_STRING, or
UTF8_STRING, whichever data type is convenient for the
selection owner.
When a request for the targets STRING, COMPOUND_TEXT,
or UTF8_STRING is made using the function
gui-get-selection, and neither selection-coding-system
nor next-selection-coding-system is set, the resultant strings
are decoded by the proper coding systems for those targets:
iso-8859-1, compound-text-with-extensions and
utf-8 respectively.
In addition to the targets specified above (and the many targets
used by various programs for their own purposes), several popular
programs and toolkits have defined selection data types of their own,
without consulting the appropriate X standards bodies. These targets
are generally named after such MIME types as text/html or
image/jpeg; they have been witnessed returning the following
forms of data:
file:// URIs (or conceivably newline or NUL terminated lists of
URIs) identifying files in the appropriate format.
These selection targets were first used by Netscape, but are now proffered by all kinds of programs, especially those based on recent versions of the GTK+ or Qt toolkits.
Emacs is also capable of serving as a selection owner. When
gui-set-selection is called, the selection data provided is
recorded internally and Emacs obtains ownership of the selection being
set.
Alist of selection targets to “selection converter” functions. When a selection request is received, Emacs looks up the selection converter pertaining to the requested selection target.
Selection converters are called with three arguments: the symbol
corresponding to the atom identifying the selection being requested,
the selection target that is being requested, and the value set with
gui-set-selection. The values which they must return are
either conses of symbols designating the data type and numbers,
symbols, vectors of numbers or symbols, or the cdrs of such conses by
themselves.
If a selection converter’s value is the special symbol NULL,
the data type returned to its requestor is set to NULL, and no
data is sent in response.
If such a value is a string, it must be a unibyte string; should no
data type be explicitly specified, the data is transferred to its
requestor with the type STRING.
If it is a symbol, its “atom” is retrieved, and it is transferred to
its requestor as a 32-bit value—if no data type is specified, its
type is ATOM.
If it is a number between -32769 and 32768, it is
transferred to its requestor as a 16 bit value—if no data type is
specified, its type is INTEGER.
If it is any other number, it is accounted a 32 bit value. Even if
the number returned is unsigned, its requestor will treat words of
type INTEGER as signed. To return an unsigned value, specify
the type CARDINAL in its place.
If it is a vector of symbols or numbers, the response to its requestor will be a list of multiple atoms or numbers. The data type returned when not expressly set is that of the list’s first element.
By default, Emacs is configured with selection converters for the following selection targets:
TEXTThis selection converter returns selection data as:
C_STRING, if the selection contents contain no
multibyte characters, or contain “raw 8-bit bytes” (see Text Representations).
STRING, if the selection contents can be
represented as ISO-Latin-1 text.
COMPOUND_TEXT, if the selection contents can
be encoded in the X Consortium’s Compound Text Encoding, and
selection-coding-system or next-selection-coding-system
is set to a coding system whose :mime-charset property is
x-ctext.
UTF8_STRING otherwise.
COMPOUND_TEXTThis selection converter returns selection data as a string of type
COMPOUND_TEXT.
STRINGThis selection converter returns selection data as a string of type
STRING, encoded in ISO-Latin-1 format.
UTF8_STRINGThis selection converter returns selection data in UTF-8 format.
text/plaintext/plain;charset=utf-8text/uri-listtext/x-xdnd-usernameXmTRANSFER_SUCCESSXmTRANSFER_FAILUREFILE_DT_NETFILEThese selection converters are used for internal purposes during
drag-and-drop operations and are not available for selections other
than XdndSelection.
TARGETSThis selection converter returns a list of atoms, one for each selection target understood by Emacs.
MULTIPLEThis selection converter is implemented in C code and is used to implement efficient transfer of selection requests which specify multiple selection targets at the same time.
LENGTHThis selection converter returns the length of the selection data, in bytes.
DELETEThis selection converter is used for internal purposes during drag-and-drop operations.
FILE_NAMEThis selection converter returns the file name of the buffer containing the selection data.
CHARACTER_POSITIONThis selection converter returns the character positions of each end of the selection in the buffer containing the selection data.
LINE_NUMBERCOLUMN_NUMBERThis selection converter returns the line and column numbers of each end of the selection in the buffer containing the selection data.
OWNER_OSThis selection converter returns the name of the operating system on which Emacs is running.
HOST_NAMEThis selection converter returns the fully-qualified domain name of the machine on which Emacs is running.
USERThis selection converter returns the username of the user account under which Emacs is running.
CLASSNAMEThese selection converters return the resource class and name used by Emacs.
INTEGERThis selection converter returns an integer value verbatim.
SAVE_TARGETS_EMACS_INTERNALThese selection converters are used for internal purposes.
With the exception of INTEGER, all selection converters
expect the data provided to gui-set-selection to be one of the
following:
(beg end buf), where
beg and end are two markers or overlays describing the
bounds of the selection data in the buffer buf.
Selections under such window systems as MS-Windows, Nextstep, Haiku
and Android are not aligned with those under X. Each of these window
system improvises its own selection mechanism without employing the
“selection converter” mechanism illustrated in the preceding node.
Only the PRIMARY, CLIPBOARD, and SECONDARY
selections are generally supported, with the XdndSelection
selection that records drag-and-drop data also available under
Nextstep and Haiku.
GTK seeks to emulate the X selection system, but its emulations are not altogether dependable, with the overall quality of each subject to the GDK backend being used. Therefore, Emacs built with PGTK will supply the same selection interface as Emacs built with X, but many selection targets will not be useful.
Although a clipboard exists, there is no concept of primary or secondary selections within the MS-Windows operating system. On this system, Emacs simulates the presence of a primary and secondary selection, while saving to and retrieving from the clipboard when so requested.
The simulation of the primary and secondary selections is conducted
by saving values supplied to gui-set-selection within the
x-selections property of the symbol designating the pertinent
selection, namely the type argument to gui-get-selection.
Each subsequent call to gui-get-selection in turn returns its
value, which is not subject to further examination (such as type
checks and the like). Under such circumstances, data-type
argument is generally disregarded. (But see below for the
qualification regarding TARGETS.)
Where the clipboard selection is concerned (whenever type is
CLIPBOARD), gui-set-selection verifies that the value
provided is a string and saves it within the system clipboard once it
is encoded by the coding system configured in
selection-coding-system. Callers of gui-get-selection
are required to set data-type to either STRING or
TARGETS.
When data-type is set to TARGETS in a call to
gui-get-selection, a vector of symbols is returned when
selection data exists, much as it is under X. It is impossible to
request clipboard data in any format besides STRING, for the
prerequisite data conversion routines are absent. Just as strings
saved into the clipboard are encoded by the
selection-coding-system, so those read from the clipboard are
decoded by that same coding system; this variable and its cousin
next-selection-coding-system merit particular scrutiny when
difficulties are encountered with saving selection text into the
clipboard.
All three selections standard in X exist in Nextstep as well, but
Emacs is only capable of saving strings to such selections.
Restrictions imposed upon calls to gui-set-selection there are
much the same as those on MS-Windows, though text is uniformly encoded
as utf-8-unix without regard to the value of
selection-coding-system. gui-get-selection is more
charitable, and accepts requests for the following selection targets:
The XdndSelection selection is also present under Nextstep,
in the form of a repository that records values supplied to
gui-set-selection. Its sole purpose is to save such values for
the fundamental drag-and-drop function x-begin-drag
(see Drag and Drop); no guarantees exist concerning its value when
read by anything else.
Selections on Haiku systems comprise all three selections customary
under X and the XdndSelection that records drag-and-drop data.
When gui-set-selection is called for the former three
selections, the data supplied is converted into a window server
“message” by a list of selection encoder functions, which is
sent to the window server.
List of selection encoder functions. When gui-set-selection is
called, each function in this list is successively called with its
selection and value arguments. If such a function returns
non-nil, its return value must be a list of the form
(key type value). In this list,
key must be the name of the data being transferred, generally
that of a MIME type, for example ‘"text/plain"’, and type
is a symbol or a number designating the type of the data; thus also
governing the interpretation of value; following is a list of
valid data types and how each of them will cause value to be
interpreted.
stringA unibyte string. The string is NULL-terminated after being placed in the message.
refA file name. The file is located and the inode identifying the file is placed in the message.
shortA 16-bit integer value.
longA 32-bit integer value.
llongA 64-bit integer value.
bytecharAn unsigned byte between 0 and 255.
size_tA number between 0 and 1 minus two to the power of the word size of the computer Emacs is running on.
ssize_tA number which fits in the C type ssize_t.
pointA cons of two floats, specifying a coordinate on-screen.
floatdoubleA single or double-precision floating point number in an unspecified format.
(haiku-numeric-enum MIME)A unibyte string containing data in a certain MIME type.
A call to gui-get-selection generally returns the data
named data-type within the selection message, albeit with
data-type replaced by an alternative name should it be one of
the following X selection targets:
STRINGThis represents Latin-1 text under X: “text/plain;charset=iso-8859-1”
UTF8_STRINGThis represents UTF-8 text: “text/plain”
If data-type is a text type such as STRING or a MIME
type matching the pattern ‘`text/*’, the string data is decoded
with the coding system apposite for it before being returned.
Furthermore, the two data types TIMESTAMP and TARGETS
are afforded special treatment; the value returned for the first is
the number of times the selection has been modified since system
startup (not a timestamp), and that for the other is a vector
of available selection data types, as elsewhere.
Much like MS-Windows, Android provides a clipboard but no primary or
secondary selection; gui-set-selection simulates the primary
and secondary selections by saving the value supplied into a variable
subsequent calls to gui-get-selection return.
From the clipboard, gui-get-selection is capable of returning
UTF-8 string data of the type STRING, the TARGETS data
type, or image and application data of any MIME type.
gui-set-selection sets only string data, much as under
MS-Windows, although this data is not affected by the value of
selection-coding-system. By contrast, only string data can be
saved to and from the primary and secondary selections; but since this
data is not communicated to programs besides Emacs, it is not subject
to encoding or decoding by any coding system.
Data saved within window system selections is not restricted to
plain text. It is possible for selection data to encompass images or
other binary data of the like, as well as rich text content instanced
by HTML, and also PostScript. Since the selection data types incident
to this data are at variance with those for plain text, the insertion
of such data is facilitated by a set of functions dubbed
yank-media handlers, which are registered by each major mode
undertaking its insertion and called where warranted upon the
execution of the yank-media command.
Register a yank-media handler which applies to the current buffer.
types can be a symbol designating a selection data type (see Accessing Selections), a regexp against which such types are matched, or a list of these symbols and regexps. For instance:
(yank-media-handler 'text/html #'my-html-handler) (yank-media-handler "image/.*" #'my-image-handler)
When a selection offers a data type matching types, the function
handler is called to insert its data, with the symbol
designating the matching selection data type, and the data returned by
gui-get-selection.
The yank-media-types command presents a list of selection data
types that are currently available, which is useful when implementing
yank-media handlers; for programs generally offer an eclectic and
seldom consistent medley of data types.
Data transferred by drag and drop is generally either plain text or a list of URLs designating files or other resources. When text is dropped, it is inserted at the location of the drop, with recourse to saving it into the kill ring if that is not possible.
URLs dropped are supplied to pertinent DND handler functions
in the variable dnd-protocol-alist, or alternatively “URL
handlers” as set forth by the variables browse-url-handlers
and browse-url-default-handlers; absent matching handlers of
either type, they are treated as plain text and inserted in the
buffer.
This variable is an alist between regexps against which URLs are matched and DND handler functions called on the dropping of matching URLs.
If a handler function is a symbol whose dnd-multiple-handler
property (see 符号属性) is set, then upon a drop it is
given a list of every URL that matches its regexp; absent this
property, it is called once for each of those URLs. Following this
first argument is one of the symbols copy, move,
link, private or ask identifying the action to be
taken.
If action is private, the program that initiated the drop
does not insist on any particular behavior on the part of its
recipient; a reasonable action to take in that case is to open the URL
or copy its contents into the current buffer. The other values of
action imply much the same as in the action argument to
dnd-begin-file-drag.
Once its work completes, a handler function must return a symbol
designating the action it took: either the action it was provided, or
the symbol private, which communicates to the source of the
drop that the action it prescribed has not been executed.
When multiple handlers match an overlapping subset of items within a drop, the handler matched against by the greatest number of items is called to open that subset. The items it is supplied are subsequently withheld from other handlers, even those they also match.
Emacs does not take measures to accept data besides text and URLs, for the window system interfaces which enable this are too far removed from each other to abstract over consistently. Nor are DND handlers accorded influence over the actions they are meant to take, as particular drag-and-drop protocols deny recipients such control. The X11 drag-and-drop implementation rests on several underlying protocols that make use of selection transfer and share much in common, to which low level access is provided through the following functions and variables:
This function is called to ascertain whether Emacs should accept a drop. It is called with three arguments:
move, copy, link or
ask, representing an action to take on the item data suggested
by the drop source. These symbols carry the same implications as in
x-begin-drag.
This function must return nil to reject the drop or a cons of
the action that will be taken (such as through transfer to a DND
handler function) and the selection data type to be requested. The
action returned in that cons may also be the symbol private,
which intimates that the action taken is as yet indeterminate.
Modifying x-dnd-test-function is generally unwarranted, for its
default set of criteria for accepting a drop can be adjusted by
changing this list of selection data types. Each element is a string,
which if found as the symbol name of an element within the list of
data types by the default “test function”, will induce that function
to accept the drop.
Introducing a new entry into this list is not useful unless a
counterpart handler function is appended to x-dnd-types-alist.
This variable is an alist between strings designating selection data types and functions which are called when things of such types are dropped.
Each such function is supplied three arguments; the first is the
window or frame below the location of the drop, as in
x-dnd-test-function; the second is the action to be taken,
which may be any of the actions returned by test functions, and third
is the selection data itself (see Accessing Selections).
Selection data types as provided by X11 drag-and-drop protocols are
sometimes distinct from those provided by the ICCCM and conforming
clipboard or primary selection owners. Frequently, the name of a MIME
type, such as "text/plain;charset=utf-8" (with discrepant
capitalization of the “utf-8”), is substituted for a standard X
selection name such as UTF8_STRING.
The X Direct Save (XDS) protocol enables programs to devolve responsibility for naming a dropped file upon the recipient. When such a drop transpires, DND handlers and the foregoing X-specific interface are largely circumvented, tasking a different function with responding to the drop.
This variable should be set to a function that registers and names files dropped using the XDS protocol in a two-step procedure. It is provided two arguments, need-name and filename.
nil, and the second argument filename
set to the basename of the file to be saved. It should return the
fully-expanded absolute file name under which to save the file. For
example, if a file is dragged to a Dired window, the natural directory
for the file is the directory of the file shown at location of the
drop. If saving the file is not possible for some reason, the
function should return nil, which will cancel the drag-and-drop
operation.
nil and the second argument filename set to the full
absolute name of the saved file. The function is then expected to do
whatever is needed given the fact that file was saved. For example,
Dired should update the directory on display by showing the new file
there.
Its default x-dnd-direct-save-function is
x-dnd-save-direct.
When called with the need-name argument non-nil, this
function prompts the user for the absolute file name under which it
should be saved. If the specified file already exists, it
additionally asks the user whether to overwrite it, and returns the
absolute file name only if the user confirms the overwriting.
When called with the need-name argument nil, it reverts
the Dired listing if the current buffer is in Dired mode or one of its
descendants, and otherwise visits the file by calling find-file
(see 访问文件的函数).
This function works like x-dnd-save-direct, but when called
with its need-name argument non-nil, it doesn’t prompt
the user for the full name of the file to be saved; instead, it
returns its argument filename expanded against the current
buffer’s default directory (see 文件名展开相关函数). (It still
asks for confirmation if a file by that name already exists in the
default directory.)
It is also possible to drag content from Emacs to other programs when this is supported by the current window-system. The functions which provide for this are as follows:
This function starts a drag-and-drop operation from frame to another program (dubbed the drop target), and returns when text is dropped or the operation is canceled.
action must be one of the symbols copy or move,
where copy means that text should be inserted by the drop
target, and move means the same as copy, but the caller
must also delete text from its source as explained in the list
below.
frame is the frame where the mouse is currently held down, or
nil, which means to use the selected frame. Since this
function might return promptly if no mouse buttons are held down, it
should be only called in response to a down-mouse-1 or
analogous event (see 鼠标事件), with frame set to the
frame where that event was generated (see 点击事件).
If allow-same-frame is nil, drops on top of frame
will be ignored.
The return value reflects the action that the drop target actually performed, and thus also what action, if any, the caller should in turn take. It is one of the following symbols:
copyThe drop target inserted the dropped text.
moveThe drop target inserted the dropped text, and the caller should delete text from the buffer where it was extracted from, if applicable.
privateThe drop target took some other unspecified action.
nilThe drag-and-drop operation was canceled.
This function starts a drag-and-drop operation from frame to another program (dubbed the drop target), and returns when file is dropped or the operation is canceled.
If file is a remote file, then a temporary local copy will be made.
action must be one of the symbols copy, move or
link, where copy means that file should be opened
or copied by the drop target, move means the drop target should
move the file to another location, and link means the drop
target should create a symbolic link to file. It is an error to
specify link as the action if file is a remote file.
frame and allow-same-frame mean the same as they do in
calls to dnd-begin-text-drag.
The return value is the action that the drop target actually performed, which is one of the following symbols:
copyThe drop target opened or copied file to a different location.
moveThe drop target moved file to a different location.
linkThe drop target (usually a file manager) created a symbolic link to file.
privateThe drop target performed some other unspecified action.
nilThe drag-and-drop operation was canceled.
This function is like dnd-begin-file-drag, except that
files is a list of files. If the drop target doesn’t support
dropping multiple files, then the first file will be used instead.
The behavior of this function is akin to that of
dnd-begin-file-drag (when the default action copy is
used), except that it accepts a name under which the copy is meant to
be filed.
The high-level interfaces described above are implemented on top of
a lower-level primitive. The low-level interface x-begin-drag
is also available for dragging content besides text and files. It
demands detailed knowledge of the data types and actions understood by
programs on each platform its callers wish to support.
This function begins a drag from frame, and returns when the
drag-and-drop operation ends, either because the drop was successful,
or because the drop was rejected. The drop occurs when all mouse
buttons are released on top of an X window other than frame (the
drop target), or any X window if allow-current-frame is
non-nil. If no mouse buttons are held down when the
drag-and-drop operation begins, this function may immediately return
nil.
targets is a list of strings representing selection targets,
much like the data-type argument to gui-get-selection,
that the drop target can request from Emacs (see Window System Selections).
action is a symbol designating the action recommended to the
target. It can either be XdndActionCopy or
XdndActionMove; both imply copying the contents of the
selection XdndSelection to the drop target, but the latter
moreover conveys a promise to delete the contents of the selection
after the copying.
action may also be an alist which associates between symbols representing available actions, and strings that the drop target presents to the user for him to select between those actions.
If return-frame is non-nil and the mouse moves over an
Emacs frame after first moving out of frame, then the frame to
which the mouse moves will be returned immediately. If
return-frame is the symbol now, then any frame beneath
the mouse pointer will be returned without waiting for the mouse to
first move out of frame. return-frame is useful when you
want to treat dragging content from one frame to another specially,
while also dragging content to other programs, but it is not
guaranteed to function on all systems and with all window managers.
If follow-tooltip is non-nil, the position of any tooltip
(such as one displayed by tooltip-show) will follow the
location of the mouse pointer as it moves during the drag-and-drop
operation. The tooltip will be hidden once all mouse buttons are
released.
If the drop was rejected or no drop target was found, this function
returns nil. Otherwise, it returns a symbol representing the
action the target opted to take, which can differ from action if
that isn’t supported by the drop target. XdndActionPrivate is
also a valid return value in addition to XdndActionCopy and
XdndActionMove; it suggests that the drop target opted for an
indeterminate action, and no further action is required of the caller.
The caller must cooperate with the target to complete the action
selected by the target. For example, callers should delete any buffer
text that was dragged if this function returns XdndActionMove,
and likewise for other drag data where comparable criteria apply.
The function x-begin-drag leverages several drag-and-drop
protocols “behind the scenes”. When dragging content that is known
to not be supported by a specific drag-and-drop protocol, that
protocol can be disabled by changing the values of the following
variables:
When this is non-nil, the Motif drag and drop protocols are
disabled, and dropping onto programs that only understand them will
not work.
When this is nil, the OffiX (old KDE) drag and drop protocol is
disabled. When this is the symbol files, the OffiX protocol
will only be used if "FILE_NAME" is one of the targets given to
x-begin-drag. Any other value means to use the OffiX protocol
to drop all supported content.
When one of the "STRING", "UTF8_STRING",
"COMPOUND_TEXT" or "TEXT" targets is present in the list
given to x-begin-drag, Emacs will try to use synthesized mouse
events and the primary selection to insert the text if the drop target
doesn’t support any drag-and-drop protocol at all.
A side effect is that Emacs will become the owner of the primary
selection upon such a drop. Such emulation can be disabled by setting
this variable to nil.
A color name is text (usually in a string) that specifies a color. Symbolic names such as ‘black’, ‘white’, ‘red’, etc., are allowed; use M-x list-colors-display to see a list of defined names. You can also specify colors numerically in forms such as ‘#rgb’ and ‘RGB:r/g/b’, where r specifies the red level, g specifies the green level, and b specifies the blue level. You can use either one, two, three, or four hex digits for r; then you must use the same number of hex digits for all g and b as well, making either 3, 6, 9 or 12 hex digits in all. (See the documentation of the X Window System for more details about numerical RGB specification of colors.)
These functions provide a way to determine which color names are valid, and what they look like. In some cases, the value depends on the selected frame, as described below; see Input Focus, for the meaning of the term “selected frame”.
To read user input of color names with completion, use
read-color (see read-color).
This function reports whether a color name is meaningful. It returns
t if so; otherwise, nil. The argument frame says
which frame’s display to ask about; if frame is omitted or
nil, the selected frame is used.
Note that this does not tell you whether the display you are using
really supports that color. When using X, you can ask for any defined
color on any kind of display, and you will get some result—typically,
the closest it can do. To determine whether a frame can really display
a certain color, use color-supported-p (see below).
This function returns a list of the color names that are defined
and supported on frame frame (default, the selected frame).
If frame does not support colors, the value is nil.
This returns t if frame can really display the color
color (or at least something close to it). If frame is
omitted or nil, the question applies to the selected frame.
Some terminals support a different set of colors for foreground and
background. If background-p is non-nil, that means you are
asking whether color can be used as a background; otherwise you
are asking whether it can be used as a foreground.
The argument color must be a valid color name.
This returns t if color is a shade of gray, as defined on
frame’s display. If frame is omitted or nil, the
question applies to the selected frame. If color is not a valid
color name, this function returns nil.
This function returns a value that describes what color should ideally look like on frame. If color is defined, the value is a list of three integers, which give the amount of red, the amount of green, and the amount of blue. Each integer ranges in principle from 0 to 65535, but some displays may not use the full range. This three-element list is called the rgb values of the color.
If color is not defined, the value is nil.
(color-values "black")
⇒ (0 0 0)
(color-values "white")
⇒ (65535 65535 65535)
(color-values "red")
⇒ (65535 0 0)
(color-values "pink")
⇒ (65535 49344 52171)
(color-values "hungry")
⇒ nil
The color values are returned for frame’s display. If
frame is omitted or nil, the information is returned for
the selected frame’s display. If the frame cannot display colors, the
value is nil.
This function does the same as color-values, but it returns
color values as floating-point numbers between 0.0 and 1.0 inclusive.
This function returns non-nil if the color described by its RGB
triplet rgb is more readable against white background than
against dark background. The argument rgb should be a list of
the form (r g b), with each component a
floating-point number in the range 0.0 to 1.0 inclusive. You can use
color-name-to-rgb to convert a color’s name to such a list.
Text terminals usually support only a small number of colors, and the computer uses small integers to select colors on the terminal. This means that the computer cannot reliably tell what the selected color looks like; instead, you have to inform your application which small integers correspond to which colors. However, Emacs does know the standard set of colors and will try to use them automatically.
The functions described in this section control how terminal colors are used by Emacs.
Several of these functions use or return rgb values, described in Color Names.
These functions accept a display (either a frame or the name of a terminal) as an optional argument. We hope in the future to make Emacs support different colors on different text terminals; then this argument will specify which terminal to operate on (the default being the selected frame’s terminal; see Input Focus). At present, though, the frame argument has no effect.
This function associates the color name name with color number number on the terminal.
The optional argument rgb, if specified, is an rgb value, a list
of three numbers that specify what the color actually looks like.
If you do not specify rgb, then this color cannot be used by
tty-color-approximate to approximate other colors, because
Emacs will not know what it looks like.
This function clears the table of defined colors for a text terminal.
This function returns an alist recording the known colors supported by a text terminal.
Each element has the form (name number . rgb)
or (name number). Here, name is the color
name, number is the number used to specify it to the terminal.
If present, rgb is a list of three color values (for red, green,
and blue) that says what the color actually looks like.
This function finds the closest color, among the known colors
supported for display, to that described by the rgb value
rgb (a list of color values). The return value is an element of
tty-color-alist.
This function finds the closest color to color among the known
colors supported for display and returns its index (an integer).
If the name color is not defined, the value is nil.
This section describes some of the functions and variables for querying and using X resources, or their equivalent on your operating system. See X Resources in The GNU Emacs Manual, for more information about X resources.
The function x-get-resource retrieves a resource value from the X
Window defaults database.
Resources are indexed by a combination of a key and a class. This function searches using a key of the form ‘instance.attribute’ (where instance is the name under which Emacs was invoked), and using ‘Emacs.class’ as the class.
The optional arguments component and subclass add to the key and the class, respectively. You must specify both of them or neither. If you specify them, the key is ‘instance.component.attribute’, and the class is ‘Emacs.class.subclass’.
This variable specifies the application name that x-get-resource
should look up. The default value is "Emacs". You can examine X
resources for other application names by binding this
variable to some other string, around a call to x-get-resource.
This variable specifies the instance name that x-get-resource
should look up. The default value is the name Emacs was invoked with,
or the value specified with the ‘-name’ or ‘-rn’ switches.
To illustrate some of the above, suppose that you have the line:
xterm.vt100.background: yellow
in your X resources file (whose name is usually ~/.Xdefaults or ~/.Xresources). Then:
(let ((x-resource-class "XTerm") (x-resource-name "xterm"))
(x-get-resource "vt100.background" "VT100.Background"))
⇒ "yellow"
(let ((x-resource-class "XTerm") (x-resource-name "xterm"))
(x-get-resource "background" "VT100" "vt100" "Background"))
⇒ "yellow"
If this variable is non-nil, Emacs does not look up X
resources, and X resources do not have any effect when creating new
frames.
The functions in this section describe the basic capabilities of a particular display. Lisp programs can use them to adapt their behavior to what the display can do. For example, a program that ordinarily uses a popup menu could use the minibuffer if popup menus are not supported.
The optional argument display in these functions specifies which
display to ask the question about. It can be a display name, a frame
(which designates the display that frame is on), or nil (which
refers to the selected frame’s display, see Input Focus).
See Color Names, Text Terminal Colors, for other functions to obtain information about displays.
This function returns t if popup menus are supported on
display, nil if not. Support for popup menus requires
that the mouse be available, since the menu is popped up by clicking
the mouse on some portion of the Emacs display.
This function returns t if display is a graphic display
capable of displaying several frames and several different fonts at
once. This is true for displays that use a window system such as X,
and false for text terminals.
This function returns t if display has a mouse available,
nil if not.
This function returns t if the screen is a color screen.
This function returns t if the screen can display shades of gray.
(All color displays can do this.)
This function returns non-nil if all the face attributes in
attributes are supported (see Face Attributes).
The definition of “supported” is somewhat heuristic, but basically means that a face containing all the attributes in attributes, when merged with the default face for display, can be represented in a way that’s
Point (2) implies that a :weight black attribute will be
satisfied by any display that can display bold, as will
:foreground "yellow" as long as some yellowish color can be
displayed, but :slant italic will not be satisfied by
the tty display code’s automatic substitution of a dim face for
italic.
This function returns t if display supports selections.
Windowed displays normally support selections, but they may also be
supported in some other cases.
This function returns t if display can display images.
Windowed displays ought in principle to handle images, but some
systems lack the support for that. On a display that does not support
images, Emacs cannot display a tool bar.
This function returns the number of screens associated with the display.
This function returns the height of the screen in pixels. On a character terminal, it gives the height in characters.
For graphical terminals, note that on multi-monitor setups this refers to the pixel height for all physical monitors associated with display. See Multiple Terminals.
This function returns the width of the screen in pixels. On a character terminal, it gives the width in characters.
For graphical terminals, note that on multi-monitor setups this refers to the pixel width for all physical monitors associated with display. See Multiple Terminals.
This function returns the height of the screen in millimeters,
or nil if Emacs cannot get that information.
For graphical terminals, note that on multi-monitor setups this refers to the height for all physical monitors associated with display. See Multiple Terminals.
This function returns the width of the screen in millimeters,
or nil if Emacs cannot get that information.
For graphical terminals, note that on multi-monitor setups this refers to the width for all physical monitors associated with display. See Multiple Terminals.
This variable allows the user to specify the dimensions of graphical
displays returned by display-mm-height and
display-mm-width in case the system provides incorrect values.
This function returns the backing store capability of the display. Backing store means recording the pixels of windows (and parts of windows) that are not exposed, so that when exposed they can be displayed very quickly.
Values can be the symbols always, when-mapped, or
not-useful. The function can also return nil
when the question is inapplicable to a certain kind of display.
This function returns non-nil if the display supports the
SaveUnder feature. That feature is used by pop-up windows
to save the pixels they obscure, so that they can pop down
quickly.
This function returns the number of planes the display supports. This is typically the number of bits per pixel. For a tty display, it is log to base two of the number of colors supported.
This function returns the visual class for the screen. The value is
one of the symbols static-gray (a limited, unchangeable number
of grays), gray-scale (a full range of grays),
static-color (a limited, unchangeable number of colors),
pseudo-color (a limited number of colors), true-color (a
full range of colors), and direct-color (a full range of
colors).
This function returns the number of color cells the screen supports.
These functions obtain additional information about the window
system in use where Emacs shows the specified display. (Their
names begin with x- for historical reasons.)
This function returns the list of version numbers of the GUI window system running on display, such as the X server on GNU and Unix systems. The value is a list of three integers: the major and minor version numbers of the protocol, and the distributor-specific release number of the window system software itself. On GNU and Unix systems, these are normally the version of the X protocol and the distributor-specific release number of the X server software. On MS-Windows, this is the version of the Windows OS.
This function returns the vendor that provided the window system software (as a string). On GNU and Unix systems this really means whoever distributes the X server. On MS-Windows this is the vendor ID string of the Windows OS (Microsoft).
When the developers of X labeled software distributors as “vendors”, they showed their false assumption that no system could ever be developed and distributed noncommercially.
A position is the index of a character in the text of a buffer. More precisely, a position identifies the place between two characters (or before the first character, or after the last character), so we can speak of the character before or after a given position. However, we often speak of the character “at” a position, meaning the character after that position.
Positions are usually represented as integers starting from 1, but can also be represented as markers—special objects that relocate automatically when text is inserted or deleted so they stay with the surrounding characters. Functions that expect an argument to be a position (an integer), but accept a marker as a substitute, normally ignore which buffer the marker points into; they convert the marker to an integer, and use that integer, exactly as if you had passed the integer as the argument, even if the marker points to the wrong buffer. A marker that points nowhere cannot convert to an integer; using it instead of an integer causes an error. See Markers.
See also the field feature (see Defining and Using Fields), which provides functions that are used by many cursor-motion commands.
Point is a special buffer position used by many editing commands, including the self-inserting typed characters and text insertion functions. Other commands move point through the text to allow editing and insertion at different places.
Like other positions, point designates a place between two characters (or before the first character, or after the last character), rather than a particular character. Usually terminals display the cursor over the character that immediately follows point; point is actually before the character on which the cursor sits.
The value of point is a number no less than 1, and no greater than the buffer size plus 1. If narrowing is in effect (see Narrowing), then point is constrained to fall within the accessible portion of the buffer (possibly at one end of it).
Each buffer has its own value of point, which is independent of the value of point in other buffers. Each window also has a value of point, which is independent of the value of point in other windows on the same buffer. This is why point can have different values in various windows that display the same buffer. When a buffer appears in only one window, the buffer’s point and the window’s point normally have the same value, so the distinction is rarely important. See Windows and Point, for more details.
This function returns the value of point in the current buffer, as an integer.
(point)
⇒ 175
This function returns the minimum accessible value of point in the current buffer. This is normally 1, but if narrowing is in effect, it is the position of the start of the region that you narrowed to. (See Narrowing.)
This function returns the maximum accessible value of point in the
current buffer. This is (1+ (buffer-size)), unless narrowing is
in effect, in which case it is the position of the end of the region
that you narrowed to. (See Narrowing.)
This function returns (point-max) if flag is greater than
0, (point-min) otherwise. The argument flag must be a
number.
This function returns the total number of characters in the current
buffer. In the absence of any narrowing (see Narrowing),
point-max returns a value one larger than this.
If you specify a buffer, buffer, then the value is the size of buffer.
(buffer-size)
⇒ 35
(point-max)
⇒ 36
Motion functions change the value of point, either relative to the current value of point, relative to the beginning or end of the buffer, or relative to the edges of the selected window. See Point.
These functions move point based on a count of characters.
goto-char is the fundamental primitive; the other functions use
that.
This function sets point in the current buffer to the value position.
If narrowing is in effect, position still counts from the
beginning of the buffer, but point cannot go outside the accessible
portion. If position is out of range, goto-char moves
point to the beginning or the end of the accessible portion.
When this function is called interactively, position is the numeric prefix argument, if provided; otherwise it is read from the minibuffer.
goto-char returns position.
This function moves point count characters forward, towards the
end of the buffer (or backward, towards the beginning of the buffer, if
count is negative). If count is nil, the default
is 1.
If this attempts to move past the beginning or end of the buffer (or
the limits of the accessible portion, when narrowing is in effect), it
signals an error with error symbol beginning-of-buffer or
end-of-buffer.
In an interactive call, count is the numeric prefix argument.
This is just like forward-char except that it moves
in the opposite direction.
The functions for parsing words described below use the syntax table
and char-script-table to decide whether a given character is
part of a word. See Syntax Tables, and see Character Properties.
This function moves point forward count words (or backward if
count is negative). If count is omitted or nil, it
defaults to 1. In an interactive call, count is specified by
the numeric prefix argument.
“Moving one word” means moving until point crosses a
word-constituent character, which indicates the beginning of a word,
and then continue moving until the word ends. By default, characters
that begin and end words, known as word boundaries, are defined
by the current buffer’s syntax table (see Table of Syntax Classes), but
modes can override that by setting up a suitable
find-word-boundary-function-table, described below. Characters
that belong to different scripts (as defined by
char-script-table), also define a word boundary
(see Character Properties). In any case, this function cannot
move point past the boundary of the accessible portion of the buffer,
or across a field boundary (see Defining and Using Fields). The most common case of
a field boundary is the end of the prompt in the minibuffer.
If it is possible to move count words, without being stopped
prematurely by the buffer boundary or a field boundary, the value is
t. Otherwise, the return value is nil and point stops at
the buffer boundary or field boundary.
If inhibit-field-text-motion is non-nil,
this function ignores field boundaries.
This function is just like forward-word, except that it moves
backward until encountering the front of a word, rather than forward.
This variable affects the behavior of forward-word and
backward-word, and everything that uses them. If it is
non-nil, then characters in the escape and character-quote
syntax classes count as part of words. Otherwise, they do not.
If this variable is non-nil, certain motion functions including
forward-word, forward-sentence, and
forward-paragraph ignore field boundaries.
This variable affects the behavior of forward-word and
backward-word, and everything that uses them. Its value is a
char-table (see 字符表) of functions to search for word
boundaries. If a character has a non-nil entry in this table,
then when a word starts or ends with that character, the corresponding
function will be called with 2 arguments: pos and limit.
The function should return the position of the other word boundary.
Specifically, if pos is smaller than limit, then pos
is at the beginning of a word, and the function should return the
position after the last character of the word; otherwise, pos is
at the last character of a word, and the function should return the
position of that word’s first character.
This function is like forward-word, but it is not affected by
find-word-boundary-function-table. Lisp programs that should
not change behavior when word movement is modified by modes which set
that table, such as subword-mode, should use this function
instead of forward-word.
This function is like backward-word, but it is not affected by
find-word-boundary-function-table. Like with
forward-word-strictly, use this function instead of
backward-word when movement by words should only consider
syntax tables.
To move point to the beginning of the buffer, write:
(goto-char (point-min))
Likewise, to move to the end of the buffer, use:
(goto-char (point-max))
Here are two commands that users use to do these things. They are documented here to warn you not to use them in Lisp programs, because they set the mark and display messages in the echo area.
This function moves point to the beginning of the buffer (or the limits of the accessible portion, when narrowing is in effect), setting the mark at the previous position (except in Transient Mark mode, if the mark is already active, it does not set the mark.)
If n is non-nil, then it puts point n tenths of the
way from the beginning of the accessible portion of the buffer. In an
interactive call, n is the numeric prefix argument, if provided;
otherwise n defaults to nil.
Warning: Don’t use this function in Lisp programs!
This function moves point to the end of the buffer (or the limits of
the accessible portion, when narrowing is in effect), setting the mark
at the previous position (except in Transient Mark mode when the mark
is already active). If n is non-nil, then it puts point
n tenths of the way from the end of the accessible portion of
the buffer.
In an interactive call, n is the numeric prefix argument,
if provided; otherwise n defaults to nil.
Warning: Don’t use this function in Lisp programs!
Text lines are portions of the buffer delimited by newline characters, which are regarded as part of the previous line. The first text line begins at the beginning of the buffer, and the last text line ends at the end of the buffer whether or not the last character is a newline. The division of the buffer into text lines is not affected by the width of the window, by line continuation in display, or by how tabs and control characters are displayed.
This function moves point to the beginning of the current line. With an
argument count not nil or 1, it moves forward
count−1 lines and then to the beginning of the line.
This function does not move point across a field boundary
(see Defining and Using Fields) unless doing so would move beyond there to a
different line; therefore, if count is nil or 1, and
point starts at a field boundary, point does not move. To ignore
field boundaries, either bind inhibit-field-text-motion to
t, or use the forward-line function instead. For
instance, (forward-line 0) does the same thing as
(beginning-of-line), except that it ignores field boundaries.
If this function reaches the end of the buffer (or of the accessible portion, if narrowing is in effect), it positions point there. No error is signaled.
Return the position that (beginning-of-line count)
would move to.
This function moves point to the end of the current line. With an
argument count not nil or 1, it moves forward
count−1 lines and then to the end of the line.
This function does not move point across a field boundary
(see Defining and Using Fields) unless doing so would move beyond there to a
different line; therefore, if count is nil or 1, and
point starts at a field boundary, point does not move. To ignore
field boundaries, bind inhibit-field-text-motion to t.
If this function reaches the end of the buffer (or of the accessible portion, if narrowing is in effect), it positions point there. No error is signaled.
Return the position that (end-of-line count)
would move to.
Like line-beginning-position, but ignores fields (and is more
efficient).
Like line-end-position, but ignores fields (and is more
efficient).
This function moves point forward count lines, to the beginning of
the line following that. If count is negative, it moves point
−count lines backward, to the beginning of a line
preceding that. If count is zero, it moves point to the
beginning of the current line. If count is nil, that
means 1.
If forward-line encounters the beginning or end of the buffer (or
of the accessible portion) before finding that many lines, it sets point
there. No error is signaled.
forward-line returns the difference between count and the
number of lines actually moved. If you attempt to move down five lines
from the beginning of a buffer that has only three lines, point stops at
the end of the last line, and the value will be 2. As an explicit
exception, if the last accessible line is non-empty, but has no
newline (e.g., if the buffer ends without a newline), the function
sets point to the end of that line, and the value returned by the
function counts that line as one line successfully moved.
In an interactive call, count is the numeric prefix argument.
This function returns the number of lines between the positions start and end in the current buffer. If start and end are equal, then it returns 0. Otherwise it returns at least 1, even if start and end are on the same line. This is because the text between them, considered in isolation, must contain at least one line unless it is empty.
If the optional ignore-invisible-lines is non-nil,
invisible lines will not be included in the count.
This function returns the number of words between the positions start and end in the current buffer.
This function can also be called interactively. In that case, it prints a message reporting the number of lines, words, and characters in the buffer, or in the region if the region is active.
This function returns the line number in the current buffer
corresponding to the buffer position pos. If pos is
nil or omitted, the current buffer position is used. If
absolute is nil, the default, counting starts at
(point-min), so the value refers to the contents of the
accessible portion of the (potentially narrowed) buffer. If
absolute is non-nil, ignore any narrowing and return
the absolute line number.
Also see the functions bolp and eolp in Examining Text Near Point.
These functions do not move point, but test whether it is already at the
beginning or end of a line.
The line functions in the previous section count text lines, delimited only by newline characters. By contrast, these functions count screen lines, which are defined by the way the text appears on the screen. A text line is a single screen line if it is short enough to fit the width of the selected window, but otherwise it may occupy several screen lines.
In some cases, text lines are truncated on the screen rather than
continued onto additional screen lines. In these cases,
vertical-motion moves point much like forward-line.
See Truncation.
Because the width of a given string depends on the flags that control
the appearance of certain characters, vertical-motion behaves
differently, for a given piece of text, depending on the buffer it is
in, and even on the selected window (because the width, the truncation
flag, and display table may vary between windows). See Usual Display Conventions.
These functions scan text to determine where screen lines break, and thus take time proportional to the distance scanned.
This function moves point to the start of the screen line count screen lines down from the screen line containing point. If count is negative, it moves up instead. If count is zero, point moves to the visual start of the current screen line.
The count argument can be a cons cell, (cols . lines), instead of an integer. Then the function moves by
lines screen lines, as described for count above, and puts
point cols columns from the visual start of that screen line.
The value of cols can be a float, and is interpreted in units of
the frame’s canonical character width (see Frame Font); this
allows specifying accurate horizontal position of point when the
target screen line uses variable fonts. Note that cols are
counted from the visual start of the line; if the window is
scrolled horizontally (see Horizontal Scrolling), the column where
point will end is in addition to the number of columns by which the
text is scrolled, and if the target line is a continuation line, its
leftmost column is considered column zero (unlike column-oriented
functions, see Counting Columns).
The return value is the number of screen lines over which point was moved. The value may be less in absolute value than count if the beginning or end of the buffer was reached.
The window window is used for obtaining parameters such as the
width, the horizontal scrolling, and the display table. But
vertical-motion always operates on the current buffer, even if
window currently displays some other buffer.
The optional argument cur-col specifies the current column when the function is called. This is the window-relative horizontal coordinate of point, measured in units of font width of the frame’s default face. Providing it speeds up the function, especially in very long lines, because the function doesn’t have to go back in the buffer in order to determine the current column. Note that cur-col is also counted from the visual start of the line.
This function returns the number of screen lines in the text from
beg to end. The number of screen lines may be different
from the number of actual lines, due to line continuation, the display
table, etc. If beg and end are nil or omitted,
they default to the beginning and end of the accessible portion of the
buffer.
If the region ends with a newline, that is ignored unless the optional
third argument count-final-newline is non-nil.
The optional fourth argument window specifies the window for obtaining parameters such as width, horizontal scrolling, and so on. The default is to use the selected window’s parameters.
Like vertical-motion, count-screen-lines always uses the
current buffer, regardless of which buffer is displayed in
window. This makes possible to use count-screen-lines in
any buffer, whether or not it is currently displayed in some window.
This function moves point with respect to the text currently displayed in the selected window. It moves point to the beginning of the screen line count screen lines from the top of the window; zero means the topmost line. If count is negative, that specifies a position −count lines from the bottom (or the last line of the buffer, if the buffer ends above the specified screen position); thus, count of −1 specifies the last fully visible screen line of the window.
If count is nil, then point moves to the beginning of the
line in the middle of the window. If the absolute value of count
is greater than the size of the window, then point moves to the place
that would appear on that screen line if the window were tall enough.
This will probably cause the next redisplay to scroll to bring that
location onto the screen.
In an interactive call, count is the numeric prefix argument.
The value returned is the screen line number point has moved to, relative to the top line of the window.
This function is like move-to-window-line, except that when the
selected window is a part of a group of windows (see Window Group), move-to-window-group-line will move to a position with
respect to the entire group, not just the single window. This
condition holds when the buffer local variable
move-to-window-group-line-function is set to a function. In
this case, move-to-window-group-line calls the function with
the argument count, then returns its result.
This function scans the current buffer, calculating screen positions. It scans the buffer forward from position from, assuming that is at screen coordinates frompos, to position to or coordinates topos, whichever comes first. It returns the ending buffer position and screen coordinates.
The coordinate arguments frompos and topos are cons cells of
the form (hpos . vpos).
The argument width is the number of columns available to display
text; this affects handling of continuation lines. nil means
the actual number of usable text columns in the window, which is
equivalent to the value returned by (window-width window).
The argument offsets is either nil or a cons cell of the
form (hscroll . tab-offset). Here hscroll is
the number of columns not being displayed at the left margin; most
callers get this by calling window-hscroll. Meanwhile,
tab-offset is the offset between column numbers on the screen and
column numbers in the buffer. This can be nonzero in a continuation
line, when the previous screen lines’ widths do not add up to a multiple
of tab-width. It is always zero in a non-continuation line.
The window window serves only to specify which display table to
use. compute-motion always operates on the current buffer,
regardless of what buffer is displayed in window.
The return value is a list of five elements:
(pos hpos vpos prevhpos contin)
Here pos is the buffer position where the scan stopped, vpos is the vertical screen position, and hpos is the horizontal screen position.
The result prevhpos is the horizontal position one character back
from pos. The result contin is t if the last line
was continued after (or within) the previous character.
For example, to find the buffer position of column col of screen line
line of a certain window, pass the window’s display start location
as from and the window’s upper-left coordinates as frompos.
Pass the buffer’s (point-max) as to, to limit the scan to
the end of the accessible portion of the buffer, and pass line and
col as topos. Here’s a function that does this:
(defun coordinates-of-position (col line)
(car (compute-motion (window-start)
'(0 . 0)
(point-max)
(cons col line)
(window-width)
(cons (window-hscroll) 0)
(selected-window))))
When you use compute-motion for the minibuffer, you need to use
minibuffer-prompt-width to get the horizontal position of the
beginning of the first screen line. See Minibuffer 内容.
Here are several functions concerned with balanced-parenthesis expressions (also called sexps in connection with moving across them in Emacs). The syntax table controls how these functions interpret various characters; see Syntax Tables. See Parsing Expressions, for lower-level primitives for scanning sexps or parts of sexps. For user-level commands, see Commands for Editing with Parentheses in The GNU Emacs Manual.
This function moves forward across arg (default 1) balanced groups of parentheses. (Other syntactic entities such as words or paired string quotes are ignored.)
This function moves backward across arg (default 1) balanced groups of parentheses. (Other syntactic entities such as words or paired string quotes are ignored.)
This function moves forward out of arg (default 1) levels of
parentheses. A negative argument means move backward but still to a
less deep spot. If escape-strings is non-nil (as it is
interactively), move out of enclosing strings as well. If
no-syntax-crossing is non-nil (as it is interactively), prefer
to break out of any enclosing string instead of moving to the start of
a list broken across multiple strings. On error, location of point is
unspecified.
This function is just like up-list, but with a negated argument.
This function moves forward into arg (default 1) levels of parentheses. A negative argument means move backward but still go deeper in parentheses (−arg levels).
This function moves forward across arg (default 1) balanced expressions. Balanced expressions include both those delimited by parentheses and other kinds, such as words and string constants. See Parsing Expressions. For example,
---------- Buffer: foo ---------- (concat∗ "foo " (car x) y z) ---------- Buffer: foo ----------
(forward-sexp 3)
⇒ nil
---------- Buffer: foo ----------
(concat "foo " (car x) y∗ z)
---------- Buffer: foo ----------
forward-sexp calls the function that is the value of the variable
forward-sexp-function, if that is non-nil, to do the
actual work, passing it the same arguments as those with which the
command was called. Major modes can define their own functions for
moving over balanced expressions as appropriate for the mode, and set
this variable to that function.
This function moves backward across arg (default 1) balanced expressions.
This function moves back to the argth beginning of a defun. If arg is negative, this actually moves forward, but it still moves to the beginning of a defun, not to the end of one. arg defaults to 1.
This function moves forward to the argth end of a defun. If arg is negative, this actually moves backward, but it still moves to the end of a defun, not to the beginning of one. arg defaults to 1.
If non-nil, this buffer-local variable holds a regular
expression that specifies what text can appear before the
open-parenthesis that starts a defun. That is to say, a defun begins
on a line that starts with a match for this regular expression,
followed by a character with open-parenthesis syntax.
If this variable’s value is non-nil, an open parenthesis in
column 0 is considered to be the start of a defun. If it is
nil, an open parenthesis in column 0 has no special meaning.
The default is t. If a string literal happens to have a
parenthesis in column 0, escape it with a backslash to avoid a false
positive.
If non-nil, this variable holds a function for finding the
beginning of a defun. The function beginning-of-defun
calls this function instead of using its normal method, passing it its
optional argument. If the argument is non-nil, the function
should move back by that many functions, like
beginning-of-defun does.
If non-nil, this variable holds a function for finding the end of
a defun. The function end-of-defun calls this function instead
of using its normal method.
If Emacs is compiled with tree-sitter, it can use the tree-sitter
parser information to move across syntax constructs. Since what
exactly is considered a defun varies between languages, a major mode
should set treesit-defun-type-regexp to determine that. Then
the mode can get navigation-by-defun functionality for free, by using
treesit-beginning-of-defun and treesit-end-of-defun.
This variable determines which nodes are considered defuns by Emacs. It can be a regexp that matches the type of defun nodes. (For “node” and “node type”, see Parsing Program Source.)
For example, python-mode sets this variable to a regexp that
matches either ‘function_definition’ or ‘class_definition’.
Sometimes not all nodes matched by the regexp are valid defuns.
Therefore, this variable can also be a cons cell of the form
(regexp . pred), where pred should be a function
that takes a node as its argument, and returns non-nil if the
node is a valid defun, or nil if it is not valid.
This variable determines how Emacs treats nested defuns. If the value
is top-level, navigation functions only move across top-level
defuns. If the value is nested, navigation functions recognize
nested defuns.
The function that is the value of the variable
forward-sentence-function determines how to move across syntax
constructs known as sentences. Major modes can assign their own
functions to this variable to customize the behavior of
forward-sentence command. If Emacs is compiled with tree-sitter,
it can use the tree-sitter parser information to move across syntax
constructs. Since what exactly is considered a sentence varies between
languages, a major mode should set treesit-thing-settings to
determine that. Then forward-sentence-function will be set to
treesit-forward-sentence, and the mode will get
navigation-by-sentence functionality for free, by using
forward-sentence and backward-sentence(see Moving by
Sentences in The extensible self-documenting text editor).
If Emacs is compiled with tree-sitter, it can use the tree-sitter
parser information to move across syntax constructs. Since what
exactly is considered a sexp varies between languages, a major mode
should set treesit-thing-settings to determine that. Then
forward-sexp-function will be set to treesit-forward-sexp,
and the mode can get navigation-by-sexp functionality for free, by using
forward-sexp and backward-sexp(see Expressions in The extensible self-documenting text editor).
The following two functions move point over a specified set of characters. For example, they are often used to skip whitespace. For related functions, see Motion and Syntax.
These functions convert the set string to multibyte if the buffer is multibyte, and they convert it to unibyte if the buffer is unibyte, as the search functions do (see Searching and Matching).
This function moves point in the current buffer forward, skipping over a given set of characters. It examines the character following point, then advances point if the character matches character-set. This continues until it reaches a character that does not match. The function returns the number of characters moved over.
The argument character-set is a string, like the inside of a
‘[…]’ in a regular expression except that ‘]’ does not
terminate it, and ‘\’ quotes ‘^’, ‘-’ or ‘\’.
Thus, "a-zA-Z" skips over all letters, stopping before the
first nonletter, and "^a-zA-Z" skips nonletters stopping before
the first letter (see Regular Expressions). Character classes
can also be used, e.g., "[:alnum:]" (see Character Classes).
If limit is supplied (it must be a number or a marker), it specifies the maximum position in the buffer that point can be skipped to. Point will stop at or before limit.
In the following example, point is initially located directly before the ‘T’. After the form is evaluated, point is located at the end of that line (between the ‘t’ of ‘hat’ and the newline). The function skips all letters and spaces, but not newlines.
---------- Buffer: foo ---------- I read "∗The cat in the hat comes back" twice. ---------- Buffer: foo ----------
(skip-chars-forward "a-zA-Z ")
⇒ 18
---------- Buffer: foo ----------
I read "The cat in the hat∗
comes back" twice.
---------- Buffer: foo ----------
This function moves point backward, skipping characters that match
character-set, until limit. It is just like
skip-chars-forward except for the direction of motion.
The return value indicates the distance traveled. It is an integer that is zero or less.
It is often useful to move point temporarily within a localized
portion of the program. This is called an excursion, and it is
done with the save-excursion special form. This construct
remembers the initial identity of the current buffer, and its value
of point, and restores them after the excursion
completes. It is the standard way to move point within one part of a
program and avoid affecting the rest of the program, and is used
thousands of times in the Lisp sources of Emacs.
If you only need to save and restore the identity of the current
buffer, use save-current-buffer or with-current-buffer
instead (see The Current Buffer). If you need to save or restore
window configurations, see the forms described in Window Configurations and in Frame Configurations.
This special form saves the identity of the current buffer and the
value of point in it, evaluates body, and finally
restores the buffer and its saved value of point. Both saved values are
restored even in case of an abnormal exit via
throw or error (see 非局部退出).
The value returned by save-excursion is the result of the last
form in body, or nil if no body forms were given.
Because save-excursion only saves point for the
buffer that was current at the start of the excursion, any changes
made to point in other buffers, during the excursion, will
remain in effect afterward. This frequently leads to unintended
consequences, so the byte compiler warns if you call set-buffer
during an excursion:
Warning: Use ‘with-current-buffer’ rather than
save-excursion+set-buffer
To avoid such problems, you should call save-excursion only
after setting the desired current buffer, as in the following example:
(defun append-string-to-buffer (string buffer)
"Append STRING to the end of BUFFER."
(with-current-buffer buffer
(save-excursion
(goto-char (point-max))
(insert string))))
Likewise, save-excursion does not restore window-buffer
correspondences altered by functions such as switch-to-buffer.
Warning: Ordinary insertion of text adjacent to the saved
point value relocates the saved value, just as it relocates all
markers. More precisely, the saved value is a marker with insertion
type nil. See Marker Insertion Types. Therefore, when the
saved point value is restored, it normally comes before the inserted
text.
This macro is like save-excursion, but also saves and restores
the mark location and mark-active. This macro does what
save-excursion did before Emacs 25.1.
Narrowing means limiting the text addressable by Emacs editing commands to a limited range of characters in a buffer. The text that remains addressable is called the accessible portion of the buffer.
Narrowing is specified with two buffer positions, which become the beginning and end of the accessible portion. For most editing commands and primitives, these positions replace the values of the beginning and end of the buffer. While narrowing is in effect, no text outside the accessible portion is displayed, and point cannot move outside the accessible portion. Note that narrowing does not alter actual buffer positions (see Point); it only determines which positions are considered the accessible portion of the buffer. Most functions refuse to operate on text that is outside the accessible portion.
Commands for saving buffers are unaffected by narrowing; they save the entire buffer regardless of any narrowing.
If you need to display in a single buffer several very different types of text, consider using an alternative facility described in Swapping Text Between Two Buffers.
This function sets the accessible portion of the current buffer to start at start and end at end. Both arguments should be character positions.
In an interactive call, start and end are set to the bounds of the current region (point and the mark, with the smallest first).
However, when the narrowing has been set by with-restriction with
a label argument (see below), narrow-to-region can be used only
within the limits of that narrowing. If start or end are
outside these limits, the corresponding limit set by
with-restriction is used instead. To gain access to other
portions of the buffer, use without-restriction with the same
label.
This function sets the accessible portion of the current buffer to
include just the current page. An optional first argument
move-count non-nil means to move forward or backward by
move-count pages and then narrow to one page. The variable
page-delimiter specifies where pages start and end
(see Standard Regular Expressions Used in Editing).
In an interactive call, move-count is set to the numeric prefix argument.
This function cancels any narrowing in the current buffer, so that the entire contents are accessible. This is called widening. It is equivalent to the following expression:
(narrow-to-region 1 (1+ (buffer-size)))
However, when a narrowing has been set by with-restriction with a
label argument (see below), the limits set by with-restriction
are restored, instead of canceling the narrowing. To gain access to
other portions of the buffer, use without-restriction with the
same label.
This function returns non-nil if the buffer is narrowed, and
nil otherwise.
This special form saves the current bounds of the accessible portion,
evaluates the body forms, and finally restores the saved bounds,
thus restoring the same state of narrowing (or absence thereof) formerly
in effect. The state of narrowing is restored even in the event of an
abnormal exit via throw or error (see 非局部退出).
Therefore, this construct is a clean way to narrow a buffer temporarily.
This construct also saves and restores the narrowings that were set by
with-restriction with a label argument (see below).
The value returned by save-restriction is that returned by the
last form in body, or nil if no body forms were given.
Caution: it is easy to make a mistake when using the
save-restriction construct. Read the entire description here
before you try it.
If body changes the current buffer, save-restriction still
restores the restrictions on the original buffer (the buffer whose
restrictions it saved from), but it does not restore the identity of the
current buffer.
save-restriction does not restore point; use
save-excursion for that. If you use both save-restriction
and save-excursion together, save-excursion should come
first (on the outside). Otherwise, the old point value would be
restored with temporary narrowing still in effect. If the old point
value were outside the limits of the temporary narrowing, this would
fail to restore it accurately.
Here is a simple example of correct use of save-restriction:
---------- Buffer: foo ---------- This is the contents of foo This is the contents of foo This is the contents of foo∗ ---------- Buffer: foo ----------
(save-excursion
(save-restriction
(goto-char 1)
(forward-line 2)
(narrow-to-region 1 (point))
(goto-char (point-min))
(replace-string "foo" "bar")))
---------- Buffer: foo ----------
This is the contents of bar
This is the contents of bar
This is the contents of foo∗
---------- Buffer: foo ----------
This special form saves the current bounds of the accessible portion of the buffer, sets the accessible portion to start at start and end at end, evaluates the body forms, and restores the saved bounds. In that case it is equivalent to
(save-restriction (narrow-to-region start end) body)
When the optional argument label, which is evaluated to get the
label to use and must yield a non-nil value, is present, the
narrowing is labeled. A labeled narrowing differs from a
non-labeled one in several ways:
narrow-to-region
and widen can be used only within the start and end
limits.
with-restriction and gain
access to other portions of the buffer, use without-restriction
with the same label argument. (Another way to gain access to
other portions of the buffer is to use an indirect buffer
(see Indirect Buffers).)
If you use with-restriction with the optional label
argument, we recommend documenting the label in the doc strings
of the functions which use it, so that other Lisp programs your code
calls could lift the labeled narrowing if and when it needs.
This special form saves the current bounds of the accessible portion of the buffer, widens the buffer, evaluates the body forms, and restores the saved bounds. In that case it is equivalent to
(save-restriction (widen) body)
When the optional argument label is present, the narrowing set
by with-restriction with the same label argument is
lifted.
A marker is a Lisp object used to specify a position in a buffer relative to the surrounding text. A marker changes its offset from the beginning of the buffer automatically whenever text is inserted or deleted, so that it stays with the two characters on either side of it.
A marker specifies a buffer and a position in that buffer. A marker can be used to represent a position in functions that require one, just as an integer could be used. In that case, the marker’s buffer is normally ignored. Of course, a marker used in this way usually points to a position in the buffer that the function operates on, but that is entirely the programmer’s responsibility. See Positions, for a complete description of positions.
A marker has three attributes: the marker position, the marker buffer, and the insertion type. The marker position is an integer that is equivalent (at a given time) to the marker as a position in that buffer. But the marker’s position value can change during the life of the marker, and often does. Insertion and deletion of text in the buffer relocate the marker. The idea is that a marker positioned between two characters remains between those two characters despite insertion and deletion elsewhere in the buffer. Relocation changes the integer equivalent of the marker.
Deleting text around a marker’s position leaves the marker between the
characters immediately before and after the deleted text. Inserting
text at the position of a marker normally leaves the marker either in
front of or after the new text, depending on the marker’s insertion
type (see Marker Insertion Types)—unless the insertion is done
with insert-before-markers (see Inserting Text).
Insertion and deletion in a buffer must check all the markers and relocate them if necessary. This slows processing in a buffer with a large number of markers. For this reason, it is a good idea to make a marker point nowhere if you are sure you don’t need it any more. Markers that can no longer be accessed are eventually removed (see Garbage Collection).
Because it is common to perform arithmetic operations on a marker
position, most of these operations (including + and
-) accept markers as arguments. In such cases, the marker
stands for its current position.
Here are examples of creating markers, setting markers, and moving point to markers:
;; Make a new marker that initially does not point anywhere:
(setq m1 (make-marker))
⇒ #<marker in no buffer>
;; Set m1 to point between the 99th and 100th characters
;; in the current buffer:
(set-marker m1 100)
⇒ #<marker at 100 in markers.texi>
;; Now insert one character at the beginning of the buffer:
(goto-char (point-min))
⇒ 1
(insert "Q")
⇒ nil
;; m1 is updated appropriately.
m1
⇒ #<marker at 101 in markers.texi>
;; Two markers that point to the same position ;; are noteq, but they areequal. (setq m2 (copy-marker m1)) ⇒ #<marker at 101 in markers.texi> (eq m1 m2) ⇒ nil (equal m1 m2) ⇒ t
;; When you are finished using a marker, make it point nowhere.
(set-marker m1 nil)
⇒ #<marker in no buffer>
You can test an object to see whether it is a marker, or whether it is either an integer or a marker. The latter test is useful in connection with the arithmetic functions that work with both markers and integers.
This function returns t if object is a marker, nil
otherwise. Note that integers are not markers, even though many
functions will accept either a marker or an integer.
This function returns t if object is an integer or a marker,
nil otherwise.
This function returns t if object is a number (either
integer or floating point) or a marker, nil otherwise.
When you create a new marker, you can make it point nowhere, or point to the present position of point, or to the beginning or end of the accessible portion of the buffer, or to the same place as another given marker.
The next four functions all return markers with insertion type
nil. See Marker Insertion Types.
This function returns a newly created marker that does not point anywhere.
(make-marker)
⇒ #<marker in no buffer>
This function returns a new marker that points to the present position
of point in the current buffer. See Point. For an example, see
copy-marker, below.
This function returns a new marker that points to the beginning of the accessible portion of the buffer. This will be the beginning of the buffer unless narrowing is in effect. See Narrowing.
This function returns a new marker that points to the end of the accessible portion of the buffer. This will be the end of the buffer unless narrowing is in effect. See Narrowing.
Here are examples of this function and point-min-marker, shown in
a buffer containing a version of the source file for the text of this
chapter.
(point-min-marker)
⇒ #<marker at 1 in markers.texi>
(point-max-marker)
⇒ #<marker at 24080 in markers.texi>
(narrow-to-region 100 200)
⇒ nil
(point-min-marker)
⇒ #<marker at 100 in markers.texi>
(point-max-marker)
⇒ #<marker at 200 in markers.texi>
If passed a marker as its argument, copy-marker returns a
new marker that points to the same place and the same buffer as does
marker-or-integer. If passed an integer as its argument,
copy-marker returns a new marker that points to position
marker-or-integer in the current buffer.
The new marker’s insertion type is specified by the argument insertion-type. See Marker Insertion Types.
(copy-marker 0)
⇒ #<marker at 1 in markers.texi>
(copy-marker 90000)
⇒ #<marker at 24080 in markers.texi>
An error is signaled if marker is neither a marker nor an integer.
Two distinct markers are considered equal (even though not
eq) to each other if they have the same position and buffer, or
if they both point nowhere.
(setq p (point-marker))
⇒ #<marker at 2139 in markers.texi>
(setq q (copy-marker p))
⇒ #<marker at 2139 in markers.texi>
(eq p q)
⇒ nil
(equal p q)
⇒ t
This section describes the functions for accessing the components of a marker object.
This function returns the position that marker points to, or
nil if it points nowhere.
This function returns the last known position of marker in its
buffer. It behaves like marker-position with one exception: if
the buffer of marker has been killed, it returns the last position
of marker in that buffer before the buffer was killed, instead of
returning nil.
This function returns the buffer that marker points into, or
nil if it points nowhere.
(setq m (make-marker))
⇒ #<marker in no buffer>
(marker-position m)
⇒ nil
(marker-buffer m)
⇒ nil
(set-marker m 3770 (current-buffer))
⇒ #<marker at 3770 in markers.texi>
(marker-buffer m)
⇒ #<buffer markers.texi>
(marker-position m)
⇒ 3770
When you insert text directly at the place where a marker points,
there are two possible ways to relocate that marker: it can point before
the inserted text, or point after it. You can specify which one a given
marker should do by setting its insertion type. Note that use of
insert-before-markers ignores markers’ insertion types, always
relocating a marker to point after the inserted text.
This function sets the insertion type of marker marker to
type. If type is t, marker will advance when
text is inserted at its position. If type is nil,
marker does not advance when text is inserted there.
This function reports the current insertion type of marker.
All functions that create markers without accepting an argument that
specifies the insertion type, create them with insertion type
nil (see Functions that Create Markers). Also, the mark has, by
default, insertion type nil.
This section describes how to change the position of an existing marker. When you do this, be sure you know whether the marker is used outside of your program, and, if so, what effects will result from moving it—otherwise, confusing things may happen in other parts of Emacs.
This function moves marker to position in buffer. If buffer is not provided, it defaults to the current buffer.
If position is nil or a marker that points nowhere, then
marker is set to point nowhere.
The value returned is marker.
(setq m (point-marker))
⇒ #<marker at 4714 in markers.texi>
(set-marker m 55)
⇒ #<marker at 55 in markers.texi>
(setq b (get-buffer "foo"))
⇒ #<buffer foo>
(set-marker m 0 b)
⇒ #<marker at 1 in foo>
This is another name for set-marker.
Each buffer has a special marker, which is designated the mark. When a buffer is newly created, this marker exists but does not point anywhere; this means that the mark doesn’t exist in that buffer yet. Subsequent commands can set the mark.
The mark specifies a position to bound a range of text for many
commands, such as kill-region and indent-rigidly. These
commands typically act on the text between point and the mark, which
is called the region. If you are writing a command that
operates on the region, don’t examine the mark directly; instead, use
interactive with the ‘r’ specification. This provides the
values of point and the mark as arguments to the command in an
interactive call, but permits other Lisp programs to specify arguments
explicitly. See interactive 的代码字符.
Some commands set the mark as a side-effect. Commands should do
this only if it has a potential use to the user, and never for their
own internal purposes. For example, the replace-regexp command
sets the mark to the value of point before doing any replacements,
because this enables the user to move back there conveniently after
the replace is finished.
Once the mark exists in a buffer, it normally never ceases to
exist. However, it may become inactive, if Transient Mark mode
is enabled. The buffer-local variable mark-active, if
non-nil, means that the mark is active. A command can call the
function deactivate-mark to deactivate the mark directly, or it
can request deactivation of the mark upon return to the editor command
loop by setting the variable deactivate-mark to a
non-nil value.
If Transient Mark mode is enabled, certain editing commands that normally apply to text near point, apply instead to the region when the mark is active. This is the main motivation for using Transient Mark mode. (Another is that this enables highlighting of the region when the mark is active. See Emacs Display.)
In addition to the mark, each buffer has a mark ring which is a
list of markers containing previous values of the mark. When editing
commands change the mark, they should normally save the old value of the
mark on the mark ring. The variable mark-ring-max specifies the
maximum number of entries in the mark ring; once the list becomes this
long, adding a new element deletes the last element.
There is also a separate global mark ring, but that is used only in a few particular user-level commands, and is not relevant to Lisp programming. So we do not describe it here.
This function returns the current buffer’s mark position as an integer,
or nil if no mark has ever been set in this buffer.
If Transient Mark mode is enabled, and mark-even-if-inactive is
nil, mark signals an error if the mark is inactive.
However, if force is non-nil, then mark disregards
inactivity of the mark, and returns the mark position (or nil)
anyway.
This function returns the marker that represents the current buffer’s mark. It is not a copy, it is the marker used internally. Therefore, changing this marker’s position will directly affect the buffer’s mark. Don’t do that unless that is the effect you want.
(setq m (mark-marker))
⇒ #<marker at 3420 in markers.texi>
(set-marker m 100)
⇒ #<marker at 100 in markers.texi>
(mark-marker)
⇒ #<marker at 100 in markers.texi>
Like any marker, this marker can be set to point at any buffer you like. If you make it point at any buffer other than the one of which it is the mark, it will yield perfectly consistent, but rather odd, results. We recommend that you not do it!
This function sets the mark to position, and activates the mark. The old value of the mark is not pushed onto the mark ring.
Please note: Use this function only if you want the user to
see that the mark has moved, and you want the previous mark position to
be lost. Normally, when a new mark is set, the old one should go on the
mark-ring. For this reason, most applications should use
push-mark and pop-mark, not set-mark.
Novice Emacs Lisp programmers often try to use the mark for the wrong purposes. The mark saves a location for the user’s convenience. An editing command should not alter the mark unless altering the mark is part of the user-level functionality of the command. (And, in that case, this effect should be documented.) To remember a location for internal use in the Lisp program, store it in a Lisp variable. For example:
(let ((beg (point))) (forward-line 1) (delete-region beg (point))).
This function sets the current buffer’s mark to position, and
pushes a copy of the previous mark onto mark-ring. If
position is nil, then the value of point is used.
The function push-mark normally does not activate the
mark. To do that, specify t for the argument activate.
A ‘Mark set’ message is displayed unless nomsg is
non-nil.
This function pops off the top element of mark-ring and makes
that mark become the buffer’s actual mark. This does not move point in
the buffer, and it does nothing if mark-ring is empty. It
deactivates the mark.
This variable, if non-nil, enables Transient Mark mode. In
Transient Mark mode, every buffer-modifying primitive sets
deactivate-mark. As a consequence, most commands that modify
the buffer also deactivate the mark.
When Transient Mark mode is enabled and the mark is active, many
commands that normally apply to the text near point instead apply to
the region. Such commands should use the function use-region-p
to test whether they should operate on the region. See The Region.
Lisp programs can set transient-mark-mode to non-nil,
non-t values to enable Transient Mark mode temporarily. If the
value is lambda, Transient Mark mode is automatically turned
off after any action, such as buffer modification, that would normally
deactivate the mark. If the value is (only . oldval),
then transient-mark-mode is set to the value oldval after
any subsequent command that moves point and is not shift-translated
(see shift-translation), or after any other
action that would normally deactivate the mark. (Marking a region
with the mouse will temporarily enable transient-mark-mode in
this way.)
If this is non-nil, Lisp programs and the Emacs user can use the
mark even when it is inactive. This option affects the behavior of
Transient Mark mode. When the option is non-nil, deactivation of
the mark turns off region highlighting, but commands that use the mark
behave as if the mark were still active.
If an editor command sets this variable non-nil, then the editor
command loop deactivates the mark after the command returns (if
Transient Mark mode is enabled). All the primitives that change the
buffer set deactivate-mark, to deactivate the mark when the
command is finished. Setting this variable makes it buffer-local.
To write Lisp code that modifies the buffer without causing
deactivation of the mark at the end of the command, bind
deactivate-mark to nil around the code that does the
modification. For example:
(let (deactivate-mark) (insert " "))
If Transient Mark mode is enabled or force is non-nil,
this function deactivates the mark and runs the normal hook
deactivate-mark-hook. Otherwise, it does nothing.
The mark is active when this variable is non-nil. This
variable is always buffer-local in each buffer. Do not use the
value of this variable to decide whether a command that normally
operates on text near point should operate on the region instead. Use
the function use-region-p for that (see The Region).
These normal hooks are run, respectively, when the mark becomes active
and when it becomes inactive. The hook activate-mark-hook is
also run when the region is reactivated, for instance after using a
command that switches back to a buffer that has an active mark.
This function implements the shift-selection behavior of
point-motion commands. See Shift Selection in The GNU Emacs
Manual. It is called automatically by the Emacs command loop
whenever a command with a ‘^’ character in its interactive
spec is invoked, before the command itself is executed
(see ^).
If shift-select-mode is non-nil and the current command
was invoked via shift translation (see shift-translation), this function sets the mark and temporarily
activates the region, unless the region was already temporarily
activated in this way. Otherwise, if the region has been activated
temporarily, it deactivates the mark and restores the variable
transient-mark-mode to its earlier value.
The value of this buffer-local variable is the list of saved former marks of the current buffer, most recent first.
mark-ring
⇒ (#<marker at 11050 in markers.texi>
#<marker at 10832 in markers.texi>
...)
The value of this variable is the maximum size of mark-ring. If
more marks than this are pushed onto the mark-ring,
push-mark discards an old mark when it adds a new one.
When Delete Selection mode (see Delete Selection in The GNU Emacs Manual) is enabled, commands that operate on the
active region (a.k.a. “selection”) behave slightly differently.
This works by adding the function delete-selection-pre-hook to
the pre-command-hook (see 命令循环概述). That function
calls delete-selection-helper to delete the selection as
appropriate for the command. If you want to adapt a command to Delete
Selection mode, put the delete-selection property on the
function’s symbol (see 访问符号属性); commands that don’t have
this property on their symbol won’t delete the selection. This
property can have one of several values to tailor the behavior to what
the command is supposed to do; see the doc strings of
delete-selection-pre-hook and delete-selection-helper
for the details.
The text between point and the mark is known as the region. Various functions operate on text delimited by point and the mark, but only those functions specifically related to the region itself are described here.
The next two functions signal an error if the mark does not point
anywhere. If Transient Mark mode is enabled and
mark-even-if-inactive is nil, they also signal an error
if the mark is inactive.
This function returns the position of the beginning of the region (as an integer). This is the position of either point or the mark, whichever is smaller.
This function returns the position of the end of the region (as an integer). This is the position of either point or the mark, whichever is larger.
Instead of using region-beginning and region-end, a
command designed to operate on a region should normally use
interactive with the ‘r’ specification to find the
beginning and end of the region. This lets other Lisp programs
specify the bounds explicitly as arguments. See interactive 的代码字符.
This function returns t if Transient Mark mode is enabled, the
mark is active, and there is a valid region in the buffer. This
function is intended to be used by commands that operate on the
region, instead of on text near point, when the mark is active.
A region is valid if it has a non-zero size, or if the user option
use-empty-active-region is non-nil (by default, it is
nil). The function region-active-p is similar to
use-region-p, but considers all regions as valid. In most
cases, you should not use region-active-p, since if the region
is empty it is often more appropriate to operate on point.
This chapter describes the functions that deal with the text in a buffer. Most examine, insert, or delete text in the current buffer, often operating at point or on text adjacent to point. Many are interactive. All the functions that change the text provide for undoing the changes (see Undo).
Many text-related functions operate on a region of text defined by two
buffer positions passed in arguments named start and end.
These arguments should be either markers (see Markers) or numeric
character positions (see Positions). The order of these arguments
does not matter; it is all right for start to be the end of the
region and end the beginning. For example, (delete-region 1
10) and (delete-region 10 1) are equivalent. An
args-out-of-range error is signaled if either start or
end is outside the accessible portion of the buffer. In an
interactive call, point and the mark are used for these arguments.
Throughout this chapter, “text” refers to the characters in the buffer, together with their properties (when relevant). Keep in mind that point is always between two characters, and the cursor appears on the character after point.
Many functions are provided to look at the characters around point.
Several simple functions are described here. See also looking-at
in Regular Expression Searching.
In the following four functions, “beginning” or “end” of buffer refers to the beginning or end of the accessible portion.
This function returns the character in the current buffer at (i.e.,
immediately after) position position. If position is out of
range for this purpose, either before the beginning of the buffer, or at
or beyond the end, then the value is nil. The default for
position is point.
In the following example, assume that the first character in the buffer is ‘@’:
(string (char-after 1))
⇒ "@"
This function returns the character in the current buffer immediately
before position position. If position is out of range for
this purpose, either at or before the beginning of the buffer, or beyond
the end, then the value is nil. The default for
position is point.
This function returns the character following point in the current
buffer. This is similar to (char-after (point)). However, if
point is at the end of the buffer, then following-char returns 0.
Remember that point is always between characters, and the cursor
normally appears over the character following point. Therefore, the
character returned by following-char is the character the
cursor is over.
In this example, point is between the ‘a’ and the ‘c’.
---------- Buffer: foo ---------- Gentlemen may cry ``Pea∗ce! Peace!,'' but there is no peace. ---------- Buffer: foo ----------
(string (preceding-char))
⇒ "a"
(string (following-char))
⇒ "c"
This function returns the character preceding point in the current
buffer. See above, under following-char, for an example. If
point is at the beginning of the buffer, preceding-char returns
0.
This function returns t if point is at the beginning of the
buffer. If narrowing is in effect, this means the beginning of the
accessible portion of the text. See also point-min in
Point.
This function returns t if point is at the end of the buffer.
If narrowing is in effect, this means the end of accessible portion of
the text. See also point-max in See Point.
This function returns t if point is at the beginning of a line.
See Motion by Text Lines. The beginning of the buffer (or of its accessible
portion) always counts as the beginning of a line.
This function returns t if point is at the end of a line. The
end of the buffer (or of its accessible portion) is always considered
the end of a line.
This section describes functions that allow a Lisp program to convert any portion of the text in the buffer into a string.
This function returns a string containing a copy of the text of the
region defined by positions start and end in the current
buffer. If the arguments are not positions in the accessible portion
of the buffer, buffer-substring signals an
args-out-of-range error.
Here’s an example which assumes Font-Lock mode is not enabled:
---------- Buffer: foo ---------- This is the contents of buffer foo ---------- Buffer: foo ----------
(buffer-substring 1 10)
⇒ "This is t"
(buffer-substring (point-max) 10)
⇒ "he contents of buffer foo\n"
If the text being copied has any text properties, these are copied into the string along with the characters they belong to. See Text Properties. However, overlays (see Overlays) in the buffer and their properties are ignored, not copied.
For example, if Font-Lock mode is enabled, you might get results like these:
(buffer-substring 1 10)
⇒ #("This is t" 0 1 (fontified t) 1 9 (fontified t))
This is like buffer-substring, except that it does not copy text
properties, just the characters themselves. See Text Properties.
This function returns the contents of the entire accessible portion of the current buffer, as a string. If the text being copied has any text properties, these are copied into the string along with the characters they belong to.
If you need to make sure the resulting string, when copied to a
different location, will not change its visual appearance due to
reordering of bidirectional text, use the
buffer-substring-with-bidi-context function
(see buffer-substring-with-bidi-context).
This function filters the buffer text between start and end
using a function specified by the variable
filter-buffer-substring-function, and returns the result.
The default filter function consults the obsolete wrapper hook
filter-buffer-substring-functions (see the documentation string
of the macro with-wrapper-hook for the details about this
obsolete facility). If it is nil, it returns the unaltered
text from the buffer, i.e., what buffer-substring would return.
If delete is non-nil, the function deletes the text
between start and end after copying it, like
delete-and-extract-region.
Lisp code should use this function instead of buffer-substring,
buffer-substring-no-properties,
or delete-and-extract-region when copying into user-accessible
data structures such as the kill-ring, X clipboard, and registers.
Major and minor modes can modify filter-buffer-substring-function
to alter such text as it is copied out of the buffer.
The value of this variable is a function that filter-buffer-substring
will call to do the actual work. The function receives three
arguments, the same as those of filter-buffer-substring,
which it should treat as per the documentation of that function. It
should return the filtered text (and optionally delete the source text).
The following two variables are obsoleted by
filter-buffer-substring-function, but are still supported for
backward compatibility.
This obsolete variable is a wrapper hook, whose members should be functions
that accept four arguments: fun, start, end, and
delete. fun is a function that takes three arguments
(start, end, and delete), and returns a string. In
both cases, the start, end, and delete arguments are
the same as those of filter-buffer-substring.
The first hook function is passed a fun that is equivalent to
the default operation of filter-buffer-substring, i.e., it
returns the buffer-substring between start and end and
optionally deletes the original text from the buffer. In most cases,
the hook function will call fun once, and then do its own
processing of the result. The next hook function receives a fun
equivalent to this, and so on. The actual return value is the result
of all the hook functions acting in sequence.
This function returns the symbol (or word) at or near point, as a string. The return value includes no text properties.
If the optional argument really-word is non-nil, it finds a
word; otherwise, it finds a symbol (which includes both word
characters and symbol constituent characters).
If the optional argument strict is non-nil, then point
must be in or next to the symbol or word—if no symbol or word is
there, the function returns nil. Otherwise, a nearby symbol or
word on the same line is acceptable.
Return the thing around or next to point, as a string.
The argument thing is a symbol which specifies a kind of
syntactic entity. Possibilities include symbol, list,
sexp, defun, filename, existing-filename,
url, word, sentence, whitespace,
line, page, string, and others.
When the optional argument no-properties is non-nil, this
function strips text properties from the return value.
---------- Buffer: foo ----------
Gentlemen may cry ``Pea∗ce! Peace!,''
but there is no peace.
---------- Buffer: foo ----------
(thing-at-point 'word)
⇒ "Peace"
(thing-at-point 'line)
⇒ "Gentlemen may cry ``Peace! Peace!,''\n"
(thing-at-point 'whitespace)
⇒ nil
This variable allows users and modes to tweak how
thing-at-point works. It’s an association list of things
and functions (called with zero parameters) to return that thing.
Entries for thing will be evaluated in turn until a
non-nil result is returned.
For instance, a major mode could say:
(setq-local thing-at-point-provider-alist
(append thing-at-point-provider-alist
'((url . my-mode--url-at-point))))
If no providers have a non-nil return, the thing will be
computed the standard way.
This function lets you compare portions of the text in a buffer, without copying them into strings first.
This function lets you compare two substrings of the same buffer or two
different buffers. The first three arguments specify one substring,
giving a buffer (or a buffer name) and two positions within the
buffer. The last three arguments specify the other substring in the
same way. You can use nil for buffer1, buffer2, or
both to stand for the current buffer.
The value is negative if the first substring is less, positive if the first is greater, and zero if they are equal. The absolute value of the result is one plus the index of the first differing characters within the substrings.
This function ignores case when comparing characters
if case-fold-search is non-nil. It always ignores
text properties.
Suppose you have the text ‘foobarbar haha!rara!’ in the current buffer; then in this example the two substrings are ‘rbar ’ and ‘rara!’. The value is 2 because the first substring is greater at the second character.
(compare-buffer-substrings nil 6 11 nil 16 21)
⇒ 2
Insertion means adding new text to a buffer. The inserted text goes at point—between the character before point and the character after point. Some insertion functions leave point before the inserted text, while other functions leave it after. We call the former insertion after point and the latter insertion before point.
Insertion moves markers located at positions after the insertion
point, so that they stay with the surrounding text (see Markers).
When a marker points at the place of insertion, insertion may or may
not relocate the marker, depending on the marker’s insertion type
(see Marker Insertion Types). Certain special functions such as
insert-before-markers relocate all such markers to point after
the inserted text, regardless of the markers’ insertion type.
Insertion functions signal an error if the current buffer is read-only (see Read-Only Buffers) or if they insert within read-only text (see Properties with Special Meanings).
These functions copy text characters from strings and buffers along with their properties. The inserted characters have exactly the same properties as the characters they were copied from. By contrast, characters specified as separate arguments, not part of a string or buffer, inherit their text properties from the neighboring text.
The insertion functions convert text from unibyte to multibyte in order to insert in a multibyte buffer, and vice versa—if the text comes from a string or from a buffer. However, they do not convert unibyte character codes 128 through 255 to multibyte characters, not even if the current buffer is a multibyte buffer. See Converting Text Representations.
This function inserts the strings and/or characters args into the
current buffer, at point, moving point forward. In other words, it
inserts the text before point. An error is signaled unless all
args are either strings or characters. The value is nil.
This function inserts the strings and/or characters args into the
current buffer, at point, moving point forward. An error is signaled
unless all args are either strings or characters. The value is
nil.
This function is unlike the other insertion functions in that it relocates markers initially pointing at the insertion point, to point after the inserted text. If an overlay begins at the insertion point, the inserted text falls outside the overlay; if a nonempty overlay ends at the insertion point, the inserted text falls inside that overlay.
This command inserts count instances of character into the current buffer before point. The argument count must be an integer, and character must be a character.
If called interactively, this command prompts for character using its Unicode name or its code point. See Inserting Text in The GNU Emacs Manual.
This function does not convert unibyte character codes 128 through 255 to multibyte characters, not even if the current buffer is a multibyte buffer. See Converting Text Representations.
If inherit is non-nil, the inserted characters inherit
sticky text properties from the two characters before and after the
insertion point. See Stickiness of Text Properties.
This function inserts a portion of buffer from-buffer-or-name
into the current buffer before point. The text inserted is the region
between start (inclusive) and end (exclusive). (These
arguments default to the beginning and end of the accessible portion
of that buffer.) This function returns nil.
In this example, the form is executed with buffer ‘bar’ as the current buffer. We assume that buffer ‘bar’ is initially empty.
---------- Buffer: foo ---------- We hold these truths to be self-evident, that all ---------- Buffer: foo ----------
(insert-buffer-substring "foo" 1 20)
⇒ nil
---------- Buffer: bar ----------
We hold these truth∗
---------- Buffer: bar ----------
This is like insert-buffer-substring except that it does not
copy any text properties.
This is like insert-buffer-substring, but works in the opposite
direction: The text is copied from the current buffer into
to-buffer. The block of text is copied to the current point in
to-buffer, and point (in that buffer) is advanced to after the
end of the copied text. Is start/end is nil, the
entire text in the current buffer is copied over.
See Stickiness of Text Properties, for other insertion functions that inherit text properties from the nearby text in addition to inserting it. Whitespace inserted by indentation functions also inherits text properties.
This section describes higher-level commands for inserting text, commands intended primarily for the user but useful also in Lisp programs.
This command inserts the entire accessible contents of
from-buffer-or-name (which must exist) into the current buffer
after point. It leaves the mark after the inserted text. The value
is nil.
This command inserts the character char (the last character typed);
it does so count times, before point, and returns nil.
Most printing characters are bound to this command. In routine use,
self-insert-command is the most frequently called function in Emacs,
but programs rarely use it except to install it on a keymap.
In an interactive call, count is the numeric prefix argument.
Self-insertion translates the input character through
translation-table-for-input. See Translation of Characters.
This command calls auto-fill-function whenever that is
non-nil and the character inserted is in the table
auto-fill-chars (see Auto Filling).
This command performs abbrev expansion if Abbrev mode is enabled and
the inserted character does not have word-constituent
syntax. (See Abbrevs and Abbrev Expansion, and Table of Syntax Classes.) It is also
responsible for calling blink-paren-function when the inserted
character has close parenthesis syntax (see Blinking Parentheses).
The final thing this command does is to run the hook
post-self-insert-hook. You could use this to automatically
reindent text as it is typed, for example. The functions on this hook
can use last-command-event (see 来自命令循环的信息) to
access the character just inserted.
If any function on this hook needs to act on the region (see The Region), it should make sure Delete Selection mode (see Delete Selection in The GNU Emacs Manual) doesn’t
delete the region before post-self-insert-hook functions are
invoked. The way to do so is to add a function that returns
nil to self-insert-uses-region-functions, a special hook
that tells Delete Selection mode it should not delete the region.
Do not try substituting your own definition of
self-insert-command for the standard one. The editor command
loop handles this function specially.
This command inserts newlines into the current buffer before point. If number-of-newlines is supplied, that many newline characters are inserted. In an interactive call, number-of-newlines is the numeric prefix argument.
This command calls self-insert-command to insert newlines,
which may subsequently break the preceding line by calling
auto-fill-function (see Auto Filling). Typically what
auto-fill-function does is insert a newline; thus, the overall
result in this case is to insert two newlines at different places: one
at point, and another earlier in the line. newline does not
auto-fill if number-of-newlines is non-nil.
This command does not run the hook post-self-insert-hook unless
called interactively or interactive is non-nil.
This command indents to the left margin if that is not zero. See Margins for Filling.
The value returned is nil.
This command can be used to ensure that you have a specific number of empty lines before point. (An “empty line” is here defined as a line with no characters on it—a line with space characters isn’t an empty line.) It defaults to ensuring that there’s a single empty line before point.
If point isn’t at the beginning of a line, a newline character is inserted first. If there’s more empty lines before point than specified, the number of empty lines is reduced. Otherwise it’s increased to the specified number.
This variable controls whether overwrite mode is in effect. The value
should be overwrite-mode-textual, overwrite-mode-binary,
or nil. overwrite-mode-textual specifies textual
overwrite mode (treats newlines and tabs specially), and
overwrite-mode-binary specifies binary overwrite mode (treats
newlines and tabs like any other characters).
Deletion means removing part of the text in a buffer, without saving it in the kill ring (see The Kill Ring). Deleted text can’t be yanked, but can be reinserted using the undo mechanism (see Undo). Some deletion functions do save text in the kill ring in some special cases.
All of the deletion functions operate on the current buffer.
This function deletes the entire text of the current buffer
(not just the accessible portion), leaving it
empty. If the buffer is read-only, it signals a buffer-read-only
error; if some of the text in it is read-only, it signals a
text-read-only error. Otherwise, it deletes the text without
asking for any confirmation. It returns nil.
Normally, deleting a large amount of text from a buffer inhibits further
auto-saving of that buffer because it has shrunk. However,
erase-buffer does not do this, the idea being that the future
text is not really related to the former text, and its size should not
be compared with that of the former text.
This command deletes the text between positions start and
end in the current buffer, and returns nil. If point was
inside the deleted region, its value afterward is start.
Otherwise, point relocates with the surrounding text, as markers do.
This function deletes the text between positions start and end in the current buffer, and returns a string containing the text just deleted.
If point was inside the deleted region, its value afterward is start. Otherwise, point relocates with the surrounding text, as markers do.
This command deletes count characters directly after point, or
before point if count is negative. If killp is
non-nil, then it saves the deleted characters in the kill ring.
In an interactive call, count is the numeric prefix argument, and killp is the unprocessed prefix argument. Therefore, if a prefix argument is supplied, the text is saved in the kill ring. If no prefix argument is supplied, then one character is deleted, but not saved in the kill ring.
The value returned is always nil.
This command deletes count characters directly before point, or
after point if count is negative. If killp is
non-nil, then it saves the deleted characters in the kill ring.
In an interactive call, count is the numeric prefix argument, and killp is the unprocessed prefix argument. Therefore, if a prefix argument is supplied, the text is saved in the kill ring. If no prefix argument is supplied, then one character is deleted, but not saved in the kill ring.
The value returned is always nil.
This command deletes count characters backward, changing tabs
into spaces. When the next character to be deleted is a tab, it is
first replaced with the proper number of spaces to preserve alignment
and then one of those spaces is deleted instead of the tab. If
killp is non-nil, then the command saves the deleted
characters in the kill ring.
Conversion of tabs to spaces happens only if count is positive. If it is negative, exactly −count characters after point are deleted.
In an interactive call, count is the numeric prefix argument, and killp is the unprocessed prefix argument. Therefore, if a prefix argument is supplied, the text is saved in the kill ring. If no prefix argument is supplied, then one character is deleted, but not saved in the kill ring.
The value returned is always nil.
This option specifies how backward-delete-char-untabify should
deal with whitespace. Possible values include untabify, the
default, meaning convert a tab to many spaces and delete one;
hungry, meaning delete all tabs and spaces before point with
one command; all meaning delete all tabs, spaces and newlines
before point, and nil, meaning do nothing special for
whitespace characters.
This section describes higher-level commands for deleting text, commands intended primarily for the user but useful also in Lisp programs.
This function deletes all spaces and tabs around point. It returns
nil.
If backward-only is non-nil, the function deletes
spaces and tabs before point, but not after point.
In the following examples, we call delete-horizontal-space four
times, once on each line, with point between the second and third
characters on the line each time.
---------- Buffer: foo ---------- I ∗thought I ∗ thought We∗ thought Yo∗u thought ---------- Buffer: foo ----------
(delete-horizontal-space) ; Four times.
⇒ nil
---------- Buffer: foo ----------
Ithought
Ithought
Wethought
You thought
---------- Buffer: foo ----------
This function joins the line point is on to the previous line, deleting
any whitespace at the join and in some cases replacing it with one
space. If join-following-p is non-nil,
delete-indentation joins this line to the following line
instead. Otherwise, if beg and end are non-nil,
this function joins all lines in the region they define.
In an interactive call, join-following-p is the prefix argument,
and beg and end are, respectively, the start and end of
the region if it is active, else nil. The function returns
nil.
If there is a fill prefix, and the second of the lines being joined
starts with the prefix, then delete-indentation deletes the
fill prefix before joining the lines. See Margins for Filling.
In the example below, point is located on the line starting ‘events’, and it makes no difference if there are trailing spaces in the preceding line.
---------- Buffer: foo ---------- When in the course of human ∗ events, it becomes necessary ---------- Buffer: foo ----------
(delete-indentation)
⇒ nil
---------- Buffer: foo ---------- When in the course of human∗ events, it becomes necessary ---------- Buffer: foo ----------
After the lines are joined, the function fixup-whitespace is
responsible for deciding whether to leave a space at the junction.
This function replaces all the horizontal whitespace surrounding point
with either one space or no space, according to the context. It
returns nil.
At the beginning or end of a line, the appropriate amount of space is none. Before a character with close parenthesis syntax, or after a character with open parenthesis or expression-prefix syntax, no space is also appropriate. Otherwise, one space is appropriate. See Table of Syntax Classes.
In the example below, fixup-whitespace is called the first time
with point before the word ‘spaces’ in the first line. For the
second invocation, point is directly after the ‘(’.
---------- Buffer: foo ---------- This has too many ∗spaces This has too many spaces at the start of (∗ this list) ---------- Buffer: foo ----------
(fixup-whitespace)
⇒ nil
(fixup-whitespace)
⇒ nil
---------- Buffer: foo ---------- This has too many spaces This has too many spaces at the start of (this list) ---------- Buffer: foo ----------
This command replaces any spaces and tabs around point with a single
space, or n spaces if n is specified. It returns
nil.
This function deletes blank lines surrounding point. If point is on a blank line with one or more blank lines before or after it, then all but one of them are deleted. If point is on an isolated blank line, then it is deleted. If point is on a nonblank line, the command deletes all blank lines immediately following it.
A blank line is defined as a line containing only tabs and spaces.
delete-blank-lines returns nil.
Delete trailing whitespace in the region defined by start and end.
This command deletes whitespace characters after the last non-whitespace character in each line in the region.
If this command acts on the entire buffer (i.e., if called
interactively with the mark inactive, or called from Lisp with
end nil), it also deletes all trailing lines at the end of the
buffer if the variable delete-trailing-lines is non-nil.
Kill functions delete text like the deletion functions, but save it so that the user can reinsert it by yanking. Most of these functions have ‘kill-’ in their name. By contrast, the functions whose names start with ‘delete-’ normally do not save text for yanking (though they can still be undone); these are deletion functions.
Most of the kill commands are primarily for interactive use, and are not described here. What we do describe are the functions provided for use in writing such commands. You can use these functions to write commands for killing text. When you need to delete text for internal purposes within a Lisp function, you should normally use deletion functions, so as not to disturb the kill ring contents. See Deleting Text.
Killed text is saved for later yanking in the kill ring. This
is a list that holds a number of recent kills, not just the last text
kill. We call this a “ring” because yanking treats it as having
elements in a cyclic order. The list is kept in the variable
kill-ring, and can be operated on with the usual functions for
lists; there are also specialized functions, described in this section,
that treat it as a ring.
Some people think this use of the word “kill” is unfortunate, since it refers to operations that specifically do not destroy the entities killed. This is in sharp contrast to ordinary life, in which death is permanent and killed entities do not come back to life. Therefore, other metaphors have been proposed. For example, the term “cut ring” makes sense to people who, in pre-computer days, used scissors and paste to cut up and rearrange manuscripts. However, it would be difficult to change the terminology now.
The kill ring records killed text as strings in a list, most recent first. A short kill ring, for example, might look like this:
("some text" "a different piece of text" "even older text")
When the list reaches kill-ring-max entries in length, adding a
new entry automatically deletes the last entry.
When kill commands are interwoven with other commands, each kill command makes a new entry in the kill ring. Multiple kill commands in succession build up a single kill ring entry, which would be yanked as a unit; the second and subsequent consecutive kill commands add text to the entry made by the first one.
For yanking, one entry in the kill ring is designated the front of the ring. Some yank commands rotate the ring by designating a different element as the front. But this virtual rotation doesn’t change the list itself—the most recent entry always comes first in the list.
kill-region is the usual subroutine for killing text. Any
command that calls this function is a kill command (and should
probably have ‘kill’ in its name). kill-region puts the
newly killed text in a new element at the beginning of the kill ring or
adds it to the most recent element. It determines automatically (using
last-command) whether the previous command was a kill command,
and if so appends the killed text to the most recent entry.
The commands described below can filter the killed text before they
save it in the kill ring. They call filter-buffer-substring
(see Examining Buffer Contents) to perform the filtering. By default,
there’s no filtering, but major and minor modes and hook functions can
set up filtering, so that text saved in the kill ring is different
from what was in the buffer.
This function kills the stretch of text between start and
end; but if the optional argument region is
non-nil, it ignores start and end, and kills the
text in the current region instead. The text is deleted but saved in
the kill ring, along with its text properties. The value is always
nil.
In an interactive call, start and end are point and
the mark, and region is always non-nil, so the command
always kills the text in the current region.
If the buffer or text is read-only, kill-region modifies the kill
ring just the same, then signals an error without modifying the buffer.
This is convenient because it lets the user use a series of kill
commands to copy text from a read-only buffer into the kill ring.
If this option is non-nil, kill-region does not signal an
error if the buffer or text is read-only. Instead, it simply returns,
updating the kill ring but not changing the buffer.
This function saves the stretch of text between start and
end on the kill ring (including text properties), but does not
delete the text from the buffer. However, if the optional argument
region is non-nil, the function ignores start and
end, and saves the current region instead. It always returns
nil.
In an interactive call, start and end are point and
the mark, and region is always non-nil, so the command
always saves the text in the current region.
The command does not set this-command to kill-region, so a
subsequent kill command does not append to the same kill ring entry.
Yanking means inserting text from the kill ring, but it does not
insert the text blindly. The yank command, and related
commands, use insert-for-yank to perform special processing on
the text before it is inserted.
This function works like insert, except that it processes the
text in string according to the yank-handler text
property, as well as the variables yank-handled-properties and
yank-excluded-properties (see below), before inserting the
result into the current buffer.
string will be run through yank-transform-functions (see
below) before inserting.
This function resembles insert-buffer-substring, except that it
processes the text according to yank-handled-properties and
yank-excluded-properties. (It does not handle the
yank-handler property, which does not normally occur in buffer
text anyway.)
If you put a yank-handler text property on all or part of a
string, that alters how insert-for-yank inserts the string. If
different parts of the string have different yank-handler
values (comparison being done with eq), each substring is
handled separately. The property value must be a list of one to four
elements, with the following format (where elements after the first
may be omitted):
(function param noexclude undo)
Here is what the elements do:
When function is non-nil, it is called instead of
insert to insert the string, with one argument—the string to
insert.
If param is present and non-nil, it replaces string
(or the substring of string being processed) as the object
passed to function (or insert). For example, if
function is yank-rectangle, param should be a list
of strings to insert as a rectangle.
If noexclude is present and non-nil, that disables the
normal action of yank-handled-properties and
yank-excluded-properties on the inserted string.
If undo is present and non-nil, it is a function that will be
called by yank-pop to undo the insertion of the current object.
It is called with two arguments, the start and end of the current
region. function can set yank-undo-function to override
the undo value.
This variable specifies special text property handling conditions for
yanked text. It takes effect after the text has been inserted (either
normally, or via the yank-handler property), and prior to
yank-excluded-properties taking effect.
The value should be an alist of elements (prop
. fun). Each alist element is handled in order. The inserted
text is scanned for stretches of text having text properties eq
to prop; for each such stretch, fun is called with three
arguments: the value of the property, and the start and end positions
of the text.
The value of this variable is the list of properties to remove from
inserted text. Its default value contains properties that might lead
to annoying results, such as causing the text to respond to the mouse
or specifying key bindings. It takes effect after
yank-handled-properties.
This variable is a list of functions. Each function is called (in
order) with the string to be yanked as the argument, and should
return a (possibly transformed) string. This variable can be set
globally, but can also be used to create new commands that are
variations on yank. For instance, to create a command that
works like yank, but cleans up whitespace before inserting, you
could say something like:
(defun yank-with-clean-whitespace ()
(interactive)
(let ((yank-transform-functions
'(string-clean-whitespace)))
(call-interactively #'yank)))
This section describes higher-level commands for yanking, which are
intended primarily for the user but useful also in Lisp programs.
Both yank and yank-pop honor the
yank-excluded-properties variable and yank-handler text
property (see Yanking).
This command inserts before point the text at the front of the kill
ring. It sets the mark at the beginning of that text, using
push-mark (see The Mark), and puts point at the end.
If arg is a non-nil list (which occurs interactively when
the user types C-u with no digits), then yank inserts the
text as described above, but puts point before the yanked text and
sets the mark after it.
If arg is a number, then yank inserts the argth
most recently killed text—the argth element of the kill ring
list, counted cyclically from the front, which is considered the
first element for this purpose.
yank does not alter the contents of the kill ring, unless it
used text provided by another program, in which case it pushes that text
onto the kill ring. However if arg is an integer different from
one, it rotates the kill ring to place the yanked string at the front.
yank returns nil.
When invoked immediately after a yank or another
yank-pop, this command replaces the just-yanked entry from the
kill ring with a different entry from the kill ring. When this
command is invoked like that, the region contains text that was just
inserted by another yank command. yank-pop deletes that text
and inserts in its place a different piece of killed text. It does
not add the deleted text to the kill ring, since it is already in the
kill ring somewhere. It does however rotate the kill ring to place
the newly yanked string at the front.
If arg is nil, then the replacement text is the previous
element of the kill ring. If arg is numeric, the replacement is
the argth previous kill. If arg is negative, a more recent
kill is the replacement.
The sequence of kills in the kill ring wraps around, so if
yank-pop is invoked repeatedly and reaches the oldest kill, the
one that comes after it is the newest one, and the one before the
newest one is the oldest one.
This command can also be invoked after a command that is not a yank command. In that case, it prompts in the minibuffer for a kill-ring entry, with completion, and uses the kill ring elements as the minibuffer history (see 迷你缓冲历史). This allows the user to interactively select one of the previous kills recorded in the kill ring.
The return value is always nil.
If this variable is non-nil, the function yank-pop uses
its value instead of delete-region to delete the text
inserted by the previous yank or
yank-pop command. The value must be a function of two
arguments, the start and end of the current region.
The function insert-for-yank automatically sets this variable
according to the undo element of the yank-handler
text property, if there is one.
These functions and variables provide access to the kill ring at a lower level, but are still convenient for use in Lisp programs, because they take care of interaction with window system selections (see Window System Selections).
The function current-kill rotates the yanking pointer, which
designates the front of the kill ring, by n places (from newer
kills to older ones), and returns the text at that place in the ring.
If the optional second argument do-not-move is non-nil,
then current-kill doesn’t alter the yanking pointer; it just
returns the nth kill, counting from the current yanking pointer.
If n is zero, indicating a request for the latest kill,
current-kill calls the value of
interprogram-paste-function (documented below) before
consulting the kill ring. If that value is a function and calling it
returns a string or a list of several strings, current-kill
pushes the strings onto the kill ring and returns the first string.
It also sets the yanking pointer to point to the kill-ring entry of
the first string returned by interprogram-paste-function,
regardless of the value of do-not-move. Otherwise,
current-kill does not treat a zero value for n specially:
it returns the entry pointed at by the yanking pointer and does not
move the yanking pointer.
This function pushes the text string onto the kill ring and
makes the yanking pointer point to it. It discards the oldest entry
if appropriate. It also invokes the values of
interprogram-paste-function (subject to
the user option save-interprogram-paste-before-kill)
and interprogram-cut-function (see below).
If replace is non-nil, then kill-new replaces the
first element of the kill ring with string, rather than pushing
string onto the kill ring.
This function appends the text string to the first entry in the
kill ring and makes the yanking pointer point to the combined entry.
Normally string goes at the end of the entry, but if
before-p is non-nil, it goes at the beginning. This
function calls kill-new as a subroutine, thus causing the
values of interprogram-cut-function and possibly
interprogram-paste-function (see below) to be invoked by
extension.
This variable provides a way of transferring killed text from other
programs, when you are using a window system. Its value should be
nil or a function of no arguments.
If the value is a function, current-kill calls it to get the
most recent kill. If the function returns a non-nil value,
then that value is used as the most recent kill. If it returns
nil, then the front of the kill ring is used.
To facilitate support for window systems that support multiple
selections, this function may also return a list of strings. In that
case, the first string is used as the most recent kill, and all
the other strings are pushed onto the kill ring, for easy access by
yank-pop.
The normal use of this function is to get the window system’s
clipboard as the most recent kill, even if the selection belongs to
another application. See Window System Selections. However, if
the clipboard contents come from the current Emacs session, this
function should return nil.
This variable provides a way of communicating killed text to other
programs, when you are using a window system. Its value should be
nil or a function of one required argument.
If the value is a function, kill-new and kill-append call
it with the new first element of the kill ring as the argument.
The normal use of this function is to put newly killed text in the window system’s clipboard. See Window System Selections.
The variable kill-ring holds the kill ring contents, in the
form of a list of strings. The most recent kill is always at the front
of the list.
The kill-ring-yank-pointer variable points to a link in the
kill ring list, whose CAR is the text to yank next. We say it
identifies the front of the ring. Moving
kill-ring-yank-pointer to a different link is called
rotating the kill ring. We call the kill ring a “ring” because
the functions that move the yank pointer wrap around from the end of the
list to the beginning, or vice-versa. Rotation of the kill ring is
virtual; it does not change the value of kill-ring.
Both kill-ring and kill-ring-yank-pointer are Lisp
variables whose values are normally lists. The word “pointer” in the
name of the kill-ring-yank-pointer indicates that the variable’s
purpose is to identify one element of the list for use by the next yank
command.
The value of kill-ring-yank-pointer is always eq to one
of the links in the kill ring list. The element it identifies is the
CAR of that link. Kill commands, which change the kill ring, also
set this variable to the value of kill-ring. The effect is to
rotate the ring so that the newly killed text is at the front.
Here is a diagram that shows the variable kill-ring-yank-pointer
pointing to the second entry in the kill ring ("some text" "a
different piece of text" "yet older text").
kill-ring ---- kill-ring-yank-pointer
| |
| v
| --- --- --- --- --- ---
--> | | |------> | | |--> | | |--> nil
--- --- --- --- --- ---
| | |
| | |
| | -->"yet older text"
| |
| --> "a different piece of text"
|
--> "some text"
This state of affairs might occur after C-y (yank)
immediately followed by M-y (yank-pop).
This variable holds the list of killed text sequences, most recently killed first.
This variable’s value indicates which element of the kill ring is at the
front of the ring for yanking. More precisely, the value is a tail
of the value of kill-ring, and its CAR is the kill string
that C-y should yank.
The value of this variable is the maximum length to which the kill
ring can grow, before elements are thrown away at the end. The default
value for kill-ring-max is 120.
Most buffers have an undo list, which records all changes made
to the buffer’s text so that they can be undone. (The buffers that
don’t have one are usually special-purpose buffers for which Emacs
assumes that undoing is not useful. In particular, any buffer whose
name begins with a space has its undo recording off by default;
see Buffer Names.) All the primitives that modify the
text in the buffer automatically add elements to the front of the undo
list, which is in the variable buffer-undo-list.
This buffer-local variable’s value is the undo list of the current
buffer. A value of t disables the recording of undo information.
Here are the kinds of elements an undo list can have:
positionThis kind of element records a previous value of point; undoing this element moves point to position. Ordinary cursor motion does not make any sort of undo record, but deletion operations use these entries to record where point was before the command.
(beg . end)This kind of element indicates how to delete text that was inserted. Upon insertion, the text occupied the range beg–end in the buffer.
(text . position)This kind of element indicates how to reinsert text that was deleted.
The deleted text itself is the string text. The place to
reinsert it is (abs position). If position is
positive, point was at the beginning of the deleted text, otherwise it
was at the end. Zero or more (marker . adjustment)
elements follow immediately after this element.
(t . time-flag)This kind of element indicates that an unmodified buffer became
modified. A time-flag that is a non-integer Lisp timestamp
represents the visited file’s modification time as of
when it was previously visited or saved, using the same format as
current-time; see Time of Day.
A time-flag of 0 means the buffer does not correspond to any file;
−1 means the visited file previously did not exist.
primitive-undo uses these
values to determine whether to mark the buffer as unmodified once again;
it does so only if the file’s status matches that of time-flag.
(nil property value beg . end)This kind of element records a change in a text property. Here’s how you might undo the change:
(put-text-property beg end property value)
(marker . adjustment)This kind of element records the fact that the marker marker was relocated due to deletion of surrounding text, and that it moved adjustment character positions. If the marker’s location is consistent with the (text . position) element preceding it in the undo list, then undoing this element moves marker − adjustment characters.
(apply funname . args)This is an extensible undo item, which is undone by calling funname with arguments args.
(apply delta beg end funname . args)This is an extensible undo item, which records a change limited to the range beg to end, which increased the size of the buffer by delta characters. It is undone by calling funname with arguments args.
This kind of element enables undo limited to a region to determine whether the element pertains to that region.
nilThis element is a boundary. The elements between two boundaries are called a change group; normally, each change group corresponds to one keyboard command, and undo commands normally undo an entire group as a unit.
This function places a boundary element in the undo list. The undo
command stops at such a boundary, and successive undo commands undo
to earlier and earlier boundaries. This function returns nil.
Calling this function explicitly is useful for splitting the effects of
a command into more than one unit. For example, query-replace
calls undo-boundary after each replacement, so that the user can
undo individual replacements one by one.
Mostly, however, this function is called automatically at an appropriate time.
The editor command loop automatically calls undo-boundary just
before executing each key sequence, so that each undo normally undoes
the effects of one command. A few exceptional commands are
amalgamating: these commands generally cause small changes to
buffers, so with these a boundary is inserted only every 20th command,
allowing the changes to be undone as a group. By default, the commands
self-insert-command, which produces self-inserting input
characters (see User-Level Insertion Commands), and delete-char,
which deletes characters (see Deleting Text), are amalgamating.
Where a command affects the contents of several buffers, as may happen,
for example, when a function on the post-command-hook affects a
buffer other than the current-buffer, then undo-boundary
will be called in each of the affected buffers.
This function can be called before an amalgamating command. It
removes the previous undo-boundary if a series of such calls
have been made.
The maximum number of changes that can be amalgamated is controlled by
the amalgamating-undo-limit variable. If this variable is 1,
no changes are amalgamated.
A Lisp program can amalgamate a series of changes into a single change
group by calling undo-amalgamate-change-group (see Atomic Change Groups). Note that amalgamating-undo-limit has no effect on
the groups produced by that function.
Some buffers, such as process buffers, can change even when no
commands are executing. In these cases, undo-boundary is
normally called periodically by the timer in this variable. Setting
this variable to non-nil prevents this behavior.
This variable is normally nil, but the undo commands bind it to
t. This is so that various kinds of change hooks can tell when
they’re being called for the sake of undoing.
This is the basic function for undoing elements of an undo list. It undoes the first count elements of list, returning the rest of list.
primitive-undo adds elements to the buffer’s undo list when it
changes the buffer. Undo commands avoid confusion by saving the undo
list value at the beginning of a sequence of undo operations. Then the
undo operations use and update the saved value. The new elements added
by undoing are not part of this saved value, so they don’t interfere with
continuing to undo.
This function does not bind undo-in-progress.
This macro removes all the undo boundaries inserted during the execution of body so that it can be undone as a single step.
Some commands leave the region active after execution in such a way that
it interferes with selective undo of that command. To make undo
ignore the active region when invoked immediately after such a command,
set the property undo-inhibit-region of the command’s function
symbol to a non-nil value. See 标准符号属性.
This section describes how to enable and disable undo information for a given buffer. It also explains how the undo list is truncated automatically so it doesn’t get too big.
Recording of undo information in a newly created buffer is normally
enabled to start with; but if the buffer name starts with a space, the
undo recording is initially disabled. You can explicitly enable or
disable undo recording with the following two functions, or by setting
buffer-undo-list yourself.
This command enables recording undo information for buffer
buffer-or-name, so that subsequent changes can be undone. If no
argument is supplied, then the current buffer is used. This function
does nothing if undo recording is already enabled in the buffer. It
returns nil.
In an interactive call, buffer-or-name is the current buffer. You cannot specify any other buffer.
This function discards the undo list of buffer-or-name, and disables further recording of undo information. As a result, it is no longer possible to undo either previous changes or any subsequent changes. If the undo list of buffer-or-name is already disabled, this function has no effect.
In an interactive call, BUFFER-OR-NAME is the current buffer. You
cannot specify any other buffer. This function returns nil.
As editing continues, undo lists get longer and longer. To prevent
them from using up all available memory space, garbage collection trims
them back to size limits you can set. (For this purpose, the size
of an undo list measures the cons cells that make up the list, plus the
strings of deleted text.) Three variables control the range of acceptable
sizes: undo-limit, undo-strong-limit and
undo-outer-limit. In these variables, size is counted as the
number of bytes occupied, which includes both saved text and other
data.
This is the soft limit for the acceptable size of an undo list. The change group at which this size is exceeded is the last one kept.
This is the upper limit for the acceptable size of an undo list. The
change group at which this size is exceeded is discarded itself (along
with all older change groups). There is one exception: the very latest
change group is only discarded if it exceeds undo-outer-limit.
If at garbage collection time the undo info for the current command exceeds this limit, Emacs discards the info and displays a warning. This is a last ditch limit to prevent memory overflow.
If this variable is non-nil, when the undo info exceeds
undo-outer-limit, Emacs asks in the echo area whether to
discard the info. The default value is nil, which means to
discard it automatically.
This option is mainly intended for debugging. Garbage collection is inhibited while the question is asked, which means that Emacs might leak memory if the user waits too long before answering the question.
Filling means adjusting the lengths of lines (by moving the line
breaks) so that they are nearly (but no greater than) a specified
maximum width. Additionally, lines can be justified, which means
inserting spaces to make the left and/or right margins line up
precisely. The width is controlled by the variable fill-column.
For ease of reading, lines should be no longer than 70 or so columns.
You can use Auto Fill mode (see Auto Filling) to fill text automatically as you insert it, but changes to existing text may leave it improperly filled. Then you must fill the text explicitly.
Most of the commands in this section return values that are not
meaningful. All the functions that do filling take note of the current
left margin, current right margin, and current justification style
(see Margins for Filling). If the current justification style is
none, the filling functions don’t actually do anything.
Several of the filling functions have an argument justify.
If it is non-nil, that requests some kind of justification. It
can be left, right, full, or center, to
request a specific style of justification. If it is t, that
means to use the current justification style for this part of the text
(see current-justification, below). Any other value is treated
as full.
When you call the filling functions interactively, using a prefix
argument implies the value full for justify.
This command fills the paragraph at or after point. If
justify is non-nil, each line is justified as well.
It uses the ordinary paragraph motion commands to find paragraph
boundaries. See Paragraphs in The GNU Emacs Manual.
When region is non-nil, then if Transient Mark mode is
enabled and the mark is active, this command calls fill-region
to fill all the paragraphs in the region, instead of filling only the
current paragraph. When this command is called interactively,
region is t.
This command fills each of the paragraphs in the region from start
to end. It justifies as well if justify is
non-nil.
If nosqueeze is non-nil, that means to leave whitespace
other than line breaks untouched. If to-eop is non-nil,
that means to keep filling to the end of the paragraph—or the next hard
newline, if use-hard-newlines is enabled (see below).
The variable paragraph-separate controls how to distinguish
paragraphs. See Standard Regular Expressions Used in Editing.
Most Emacs buffers use monospaced text, so all the filling functions
(like fill-region) work based on the number of characters and
char-width. However, Emacs can render other types of things,
like text that contains images and using proportional fonts, and the
pixel-fill-region exists to handle that. It fills the region
of text between start and end at pixel granularity, so
text using variable-pitch fonts or several different fonts looks
filled regardless of different character sizes. The argument
pixel-width specifies the maximum pixel width a line is allowed
to have after filling; it is the pixel-resolution equivalent of the
fill-column in fill-region. For instance, this Lisp
snippet will insert text using a proportional font, and then fill this
to be no wider than 300 pixels:
(insert (propertize "This is a sentence that's ends here." 'face 'variable-pitch)) (pixel-fill-region (point) (point-max) 300)
If start isn’t at the start of a line, the horizontal position of start, converted to pixel units, will be used as the indentation prefix on subsequent lines.
The pixel-fill-width helper function can be used to compute the
pixel width to use. If given no arguments, it’ll return a value
slightly less than the width of the current window. The first
optional value, columns, specifies the number of columns using
the standard, monospaced fonts, for example fill-column. The second
optional value is the window to use. You’d typically use it like
this:
(pixel-fill-region start end (pixel-fill-width fill-column))
This command fills each paragraph in the region according to its individual fill prefix. Thus, if the lines of a paragraph were indented with spaces, the filled paragraph will remain indented in the same fashion.
The first two arguments, start and end, are the beginning
and end of the region to be filled. The third and fourth arguments,
justify and citation-regexp, are optional. If
justify is non-nil, the paragraphs are justified as
well as filled. If citation-regexp is non-nil, it means the
function is operating on a mail message and therefore should not fill
the header lines. If citation-regexp is a string, it is used as
a regular expression; if it matches the beginning of a line, that line
is treated as a citation marker.
Ordinarily, fill-individual-paragraphs regards each change in
indentation as starting a new paragraph. If
fill-individual-varying-indent is non-nil, then only
separator lines separate paragraphs. That mode can handle indented
paragraphs with additional indentation on the first line.
This variable alters the action of fill-individual-paragraphs as
described above.
This command considers a region of text as a single paragraph and fills
it. If the region was made up of many paragraphs, the blank lines
between paragraphs are removed. This function justifies as well as
filling when justify is non-nil.
If nosqueeze is non-nil, that means to leave whitespace
other than line breaks untouched. If squeeze-after is
non-nil, it specifies a position in the region, and means
that whitespace other than line breaks should be left untouched before
that position.
In Adaptive Fill mode, this command calls fill-context-prefix to
choose a fill prefix by default. See Adaptive Fill Mode.
This command inserts spaces between the words of the current line so
that the line ends exactly at fill-column. It returns
nil.
The argument how, if non-nil specifies explicitly the style
of justification. It can be left, right, full,
center, or none. If it is t, that means to
follow specified justification style (see current-justification,
below). nil means to do full justification.
If eop is non-nil, that means do only left-justification
if current-justification specifies full justification. This is
used for the last line of a paragraph; even if the paragraph as a
whole is fully justified, the last line should not be.
If nosqueeze is non-nil, that means do not change interior
whitespace.
This variable’s value specifies the style of justification to use for
text that doesn’t specify a style with a text property. The possible
values are left, right, full, center, or
none. The default value is left.
This function returns the proper justification style to use for filling the text around point.
This returns the value of the justification text property at
point, or the variable default-justification if there is no such
text property. However, it returns nil rather than none
to mean “don’t justify”.
If this variable is non-nil, a period followed by just one space
does not count as the end of a sentence, and the filling functions
avoid breaking the line at such a place.
If this variable is non-nil, a sentence can end without a
period. This is used for languages like Thai, where sentences end
with a double space but without a period.
If this variable is non-nil, it should be a string of
characters that can end a sentence without following spaces.
If this variable is non-nil, two words of different kind (e.g.,
English and CJK) will be separated with a space when concatenating one
that is in the end of a line and the other that is in the beginning of
the next line for filling.
This variable provides a way to override the filling of paragraphs.
If its value is non-nil, fill-paragraph calls this
function to do the work. If the function returns a non-nil
value, fill-paragraph assumes the job is done, and immediately
returns that value.
The usual use of this feature is to fill comments in programming language modes. If the function needs to fill a paragraph in the usual way, it can do so as follows:
(let ((fill-paragraph-function nil)) (fill-paragraph arg))
This variable provides a way to override how the filling functions,
such as fill-region and fill-paragraph, move forward to
the next paragraph. Its value should be a function, which is called
with a single argument n, the number of paragraphs to move, and
should return the difference between n and the number of
paragraphs actually moved. The default value of this variable is
forward-paragraph. See Paragraphs in The GNU Emacs
Manual.
If this variable is non-nil, the filling functions do not delete
newlines that have the hard text property. These hard
newlines act as paragraph separators. See Hard and Soft Newlines in The GNU Emacs Manual.
This buffer-local variable, if non-nil, specifies a string of
text that appears at the beginning of normal text lines and should be
disregarded when filling them. Any line that fails to start with the
fill prefix is considered the start of a paragraph; so is any line
that starts with the fill prefix followed by additional whitespace.
Lines that start with the fill prefix but no additional whitespace are
ordinary text lines that can be filled together. The resulting filled
lines also start with the fill prefix.
The fill prefix follows the left margin whitespace, if any.
This buffer-local variable specifies the maximum width of filled lines. Its value should be an integer, which is a number of columns. All the filling, justification, and centering commands are affected by this variable, including Auto Fill mode (see Auto Filling).
As a practical matter, if you are writing text for other people to
read, you should set fill-column to no more than 70. Otherwise
the line will be too long for people to read comfortably, and this can
make the text seem clumsy.
The default value for fill-column is 70. To disable Auto Fill
mode in a specific mode, you could say something like:
(add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
This sets the left-margin property on the text from from to
to to the value margin. If Auto Fill mode is enabled, this
command also refills the region to fit the new margin.
This sets the right-margin property on the text from from
to to to the value margin. If Auto Fill mode is enabled,
this command also refills the region to fit the new margin.
This function returns the proper left margin value to use for filling
the text around point. The value is the sum of the left-margin
property of the character at the start of the current line (or zero if
none), and the value of the variable left-margin.
This function returns the proper fill column value to use for filling
the text around point. The value is the value of the fill-column
variable, minus the value of the right-margin property of the
character after point.
This function moves point to the left margin of the current line. The
column moved to is determined by calling the function
current-left-margin. If the argument n is non-nil,
move-to-left-margin moves forward n−1 lines first.
If force is non-nil, that says to fix the line’s
indentation if that doesn’t match the left margin value.
This function removes left margin indentation from the text between
from and to. The amount of indentation to delete is
determined by calling current-left-margin. In no case does this
function delete non-whitespace. If from and to are omitted,
they default to the whole buffer.
This function adjusts the indentation at the beginning of the current
line to the value specified by the variable left-margin. (That
may involve either inserting or deleting whitespace.) This function
is the value of indent-line-function in Paragraph-Indent Text mode.
This variable specifies the base left margin column. In Fundamental mode, RET indents to this column. This variable automatically becomes buffer-local when set in any fashion.
This variable gives major modes a way to specify not to break a line
at certain places. Its value should be a list of functions. Whenever
filling considers breaking the line at a certain place in the buffer,
it calls each of these functions with no arguments and with point
located at that place. If any of the functions returns
non-nil, then the line won’t be broken there.
When Adaptive Fill Mode is enabled, Emacs determines the fill prefix automatically from the text in each paragraph being filled rather than using a predetermined value. During filling, this fill prefix gets inserted at the start of the second and subsequent lines of the paragraph as described in Filling, and in Auto Filling.
Adaptive Fill mode is enabled when this variable is non-nil.
It is t by default.
This function implements the heart of Adaptive Fill mode; it chooses a fill prefix based on the text between from and to, typically the start and end of a paragraph. It does this by looking at the first two lines of the paragraph, based on the variables described below.
Usually, this function returns the fill prefix, a string. However,
before doing this, the function makes a final check (not specially
mentioned in the following) that a line starting with this prefix
wouldn’t look like the start of a paragraph. Should this happen, the
function signals the anomaly by returning nil instead.
In detail, fill-context-prefix does this:
adaptive-fill-function (if any),
then the regular expression adaptive-fill-regexp (see below).
The first non-nil result of these, or the empty string if
they’re both nil, becomes the first line’s candidate.
adaptive-fill-first-line-regexp below).
nil.
Adaptive Fill mode matches this regular expression against the text starting after the left margin whitespace (if any) on a line; the characters it matches are that line’s candidate for the fill prefix.
The default value matches whitespace with certain punctuation characters intermingled.
Used only in one-line paragraphs, this regular expression acts as an
additional check of the validity of the one available candidate fill
prefix: the candidate must match this regular expression, or match
comment-start-skip. If it doesn’t, fill-context-prefix
replaces the candidate with a string of spaces of the same width
as it.
The default value of this variable is "\\`[ \t]*\\'", which
matches only a string of whitespace. The effect of this default is to
force the fill prefixes found in one-line paragraphs always to be pure
whitespace.
You can specify more complex ways of choosing a fill prefix
automatically by setting this variable to a function. The function is
called with point after the left margin (if any) of a line, and it
must preserve point. It should return either that line’s fill
prefix or nil, meaning it has failed to determine a prefix.
Auto Fill mode is a minor mode that fills lines automatically as text is inserted. See Auto Fill in The GNU Emacs Manual. This section describes some variables used by Auto Fill mode. For a description of functions that you can call explicitly to fill and justify existing text, see Filling.
Auto Fill mode also enables the functions that change the margins and justification style to refill portions of the text. See Margins for Filling.
The value of this buffer-local variable should be a function (of no
arguments) to be called after self-inserting a character from the table
auto-fill-chars, see below. It may be nil, in which case
nothing special is done in that case.
The value of auto-fill-function is do-auto-fill when Auto
Fill mode is enabled. That is a function whose sole purpose is to
implement the usual strategy for breaking a line.
This variable specifies the function to use for
auto-fill-function, if and when Auto Fill is turned on. Major
modes can set buffer-local values for this variable to alter how Auto
Fill works.
A char table of characters which invoke auto-fill-function when
self-inserted—space and newline in most language environments. They
have an entry t in the table.
This variable, if non-nil, means to fill lines automatically
within comments only. More precisely, this means that if a comment
syntax was defined for the current buffer, then self-inserting a
character outside of a comment will not call auto-fill-function.
The sorting functions described in this section all rearrange text in
a buffer. This is in contrast to the function sort, which
rearranges the order of the elements of a list (see 重排列表的函数).
The values returned by these functions are not meaningful.
This function is the general text-sorting routine that subdivides a buffer into records and then sorts them. Most of the commands in this section use this function.
To understand how sort-subr works, consider the whole accessible
portion of the buffer as being divided into disjoint pieces called
sort records. The records may or may not be contiguous, but they
must not overlap. A portion of each sort record (perhaps all of it) is
designated as the sort key. Sorting rearranges the records in order by
their sort keys.
Usually, the records are rearranged in order of ascending sort key.
If the first argument to the sort-subr function, reverse,
is non-nil, the sort records are rearranged in order of
descending sort key.
The next four arguments to sort-subr are functions that are
called to move point across a sort record. They are called many times
from within sort-subr.
sort-subr is
called. Therefore, you should usually move point to the beginning of
the buffer before calling sort-subr.
This function can indicate there are no more sort records by leaving point at the end of the buffer.
nil value to be used as the sort key, or
return nil to indicate that the sort key is in the buffer
starting at point. In the latter case, endkeyfun is called to
find the end of the sort key.
nil and this argument is omitted (or
nil), then the sort key extends to the end of the record. There
is no need for endkeyfun if startkeyfun returns a
non-nil value.
The argument predicate is the function to use to compare keys.
It is called with two arguments, the keys to compare, and should
return non-nil if the first key should come before the second
in the sorting order. What exactly are the key arguments depends on
what startkeyfun and endkeyfun return. If predicate
is omitted or nil, it defaults to < if the keys are
numbers, to compare-buffer-substrings if the keys are cons
cells (whose car and cdr are start and end buffer
positions of the key), and to string< otherwise (with keys
assumed to be strings).
As an example of sort-subr, here is the complete function
definition for sort-lines:
;; Note that the first two lines of doc string ;; are effectively one line when viewed by a user. (defun sort-lines (reverse beg end) "Sort lines in region alphabetically;\ argument means descending order. Called from a program, there are three arguments:
REVERSE (non-nil means reverse order),\ BEG and END (region to sort). The variable `sort-fold-case' determines\ whether alphabetic case affects the sort order."
(interactive "P\nr")
(save-excursion
(save-restriction
(narrow-to-region beg end)
(goto-char (point-min))
(let ((inhibit-field-text-motion t))
(sort-subr reverse 'forward-line 'end-of-line)))))
Here forward-line moves point to the start of the next record,
and end-of-line moves point to the end of record. We do not pass
the arguments startkeyfun and endkeyfun, because the entire
record is used as the sort key.
The sort-paragraphs function is very much the same, except that
its sort-subr call looks like this:
(sort-subr reverse
(lambda ()
(while (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
'forward-paragraph)
Markers pointing into any sort records are left with no useful
position after sort-subr returns.
If this variable is non-nil, sort-subr and the other
buffer sorting functions ignore case when comparing strings.
This command sorts the region between start and end alphabetically as specified by record-regexp and key-regexp. If reverse is a negative integer, then sorting is in reverse order.
Alphabetical sorting means that two sort keys are compared by comparing the first characters of each, the second characters of each, and so on. If a mismatch is found, it means that the sort keys are unequal; the sort key whose character is less at the point of first mismatch is the lesser sort key. The individual characters are compared according to their numerical character codes in the Emacs character set.
The value of the record-regexp argument specifies how to divide the buffer into sort records. At the end of each record, a search is done for this regular expression, and the text that matches it is taken as the next record. For example, the regular expression ‘^.+$’, which matches lines with at least one character besides a newline, would make each such line into a sort record. See Regular Expressions, for a description of the syntax and meaning of regular expressions.
The value of the key-regexp argument specifies what part of each record is the sort key. The key-regexp could match the whole record, or only a part. In the latter case, the rest of the record has no effect on the sorted order of records, but it is carried along when the record moves to its new position.
The key-regexp argument can refer to the text matched by a subexpression of record-regexp, or it can be a regular expression on its own.
If key-regexp is:
then the text matched by the digitth ‘\(...\)’ parenthesis grouping in record-regexp is the sort key.
then the whole record is the sort key.
then sort-regexp-fields searches for a match for the regular
expression within the record. If such a match is found, it is the sort
key. If there is no match for key-regexp within a record then
that record is ignored, which means its position in the buffer is not
changed. (The other records may move around it.)
For example, if you plan to sort all the lines in the region by the first word on each line starting with the letter ‘f’, you should set record-regexp to ‘^.*$’ and set key-regexp to ‘\<f\w*\>’. The resulting expression looks like this:
(sort-regexp-fields nil "^.*$" "\\<f\\w*\\>"
(region-beginning)
(region-end))
If you call sort-regexp-fields interactively, it prompts for
record-regexp and key-regexp in the minibuffer.
This command alphabetically sorts lines in the region between
start and end. If reverse is non-nil, the sort
is in reverse order.
This command alphabetically sorts paragraphs in the region between
start and end. If reverse is non-nil, the sort
is in reverse order.
This command alphabetically sorts pages in the region between
start and end. If reverse is non-nil, the sort
is in reverse order.
This command sorts lines in the region between start and end, comparing them alphabetically by the fieldth field of each line. Fields are separated by whitespace and numbered starting from 1. If field is negative, sorting is by the −fieldth field from the end of the line. This command is useful for sorting tables.
This command sorts lines in the region between start and end, comparing them numerically by the fieldth field of each line. Fields are separated by whitespace and numbered starting from 1. The specified field must contain a number in each line of the region. Numbers starting with 0 are treated as octal, and numbers starting with ‘0x’ are treated as hexadecimal.
If field is negative, sorting is by the −fieldth field from the end of the line. This command is useful for sorting tables.
This variable specifies the default radix for
sort-numeric-fields to parse numbers.
This command sorts the lines in the region between beg and end, comparing them alphabetically by a certain range of columns. The column positions of beg and end bound the range of columns to sort on.
If reverse is non-nil, the sort is in reverse order.
One unusual thing about this command is that the entire line containing position beg, and the entire line containing position end, are included in the region sorted.
Note that sort-columns rejects text that contains tabs, because
tabs could be split across the specified columns. Use M-x
untabify to convert tabs to spaces before sorting.
When possible, this command actually works by calling the sort
utility program.
The column functions convert between a character position (counting characters from the beginning of the buffer) and a column position (counting screen characters from the beginning of a line).
These functions count each character according to the number of
columns it occupies on the screen. This means control characters count
as occupying 2 or 4 columns, depending upon the value of
ctl-arrow, and tabs count as occupying a number of columns that
depends on the value of tab-width and on the column where the tab
begins. See Usual Display Conventions.
Column number computations ignore the width of the window and the
amount of horizontal scrolling. Consequently, a column value can be
arbitrarily high. The first (or leftmost) column is numbered 0. They
also ignore overlays and text properties, aside from invisibility.
Invisible text is considered as having zero width, unless
buffer-invisibility-spec specifies that invisible text should
be displayed as ellipsis (see Invisible Text).
This function returns the horizontal position of point, measured in columns, counting from 0 at the left margin. The column position is the sum of the widths of all the displayed representations of the characters between the start of the current line and point.
This function moves point to column in the current line. The calculation of column takes into account the widths of the displayed representations of the characters between the start of the line and point.
When called interactively, column is the value of prefix numeric argument. If column is not an integer, an error is signaled.
If it is impossible to move to column column because that is in
the middle of a multicolumn character such as a tab, point moves to the
end of that character. However, if force is non-nil, and
column is in the middle of a tab, then move-to-column
either converts the tab into spaces (when indent-tabs-mode is
nil), or inserts enough spaces before it (otherwise), so that
point can move precisely to column column. Other multicolumn
characters can cause anomalies despite force, since there is no
way to split them.
The argument force also has an effect if the line isn’t long
enough to reach column column; if it is t, that means to
add whitespace at the end of the line to reach that column.
The return value is the column number actually moved to.
The indentation functions are used to examine, move to, and change whitespace that is at the beginning of a line. Some of the functions can also change whitespace elsewhere on a line. Columns and indentation count from zero at the left margin.
This section describes the primitive functions used to count and insert indentation. The functions in the following sections use these primitives. See Size of Displayed Text, for related functions.
This function returns the indentation of the current line, which is the horizontal position of the first nonblank character. If the contents are entirely blank, then this is the horizontal position of the end of the line.
This function considers invisible text as having zero width, unless
buffer-invisibility-spec specifies that invisible text should
be displayed as ellipsis. See Invisible Text.
This function indents from point with tabs and spaces until column
is reached. If minimum is specified and non-nil, then at
least that many spaces are inserted even if this requires going beyond
column. Otherwise the function does nothing if point is already
beyond column. The value is the column at which the inserted
indentation ends.
The inserted whitespace characters inherit text properties from the surrounding text (usually, from the preceding text only). See Stickiness of Text Properties.
If this variable is non-nil, indentation functions can insert
tabs as well as spaces. Otherwise, they insert only spaces. Setting
this variable automatically makes it buffer-local in the current buffer.
An important function of each major mode is to customize the TAB key to indent properly for the language being edited. This section describes the mechanism of the TAB key and how to control it. The functions in this section return unpredictable values.
This is the command bound to TAB in most editing modes. Its usual action is to indent the current line, but it can alternatively insert a tab character or indent a region.
Here is what it does:
indent-region to indent all the
text in the region (see Indenting an Entire Region).
indent-line-function
is indent-to-left-margin (a trivial command that inserts a tab
character), or if the variable tab-always-indent specifies that
a tab character ought to be inserted (see below), then it inserts a
tab character.
indent-line-function. If the line is already
indented, and the value of tab-always-indent is complete
(see below), it tries completing the text at point.
If rigid is non-nil (interactively, with a prefix
argument), then after this command indents a line or inserts a tab, it
also rigidly indents the entire balanced expression which starts at
the beginning of the current line, in order to reflect the new
indentation. This argument is ignored if the command indents the
region.
This variable’s value is the function to be used by
indent-for-tab-command, and various other indentation commands,
to indent the current line. It is usually assigned by the major mode;
for instance, Lisp mode sets it to lisp-indent-line, C mode
sets it to c-indent-line, and so on. The default value is
indent-relative. See 代码自动缩进.
This command calls the function in indent-line-function to
indent the current line in a way appropriate for the current major mode.
This function inserts a newline, then indents the new line (the one
following the newline just inserted) according to the major mode. It
does indentation by calling indent-according-to-mode.
This command reindents the current line, inserts a newline at point,
and then indents the new line (the one following the newline just
inserted). It does indentation on both lines by calling
indent-according-to-mode.
This variable can be used to customize the behavior of the TAB
(indent-for-tab-command) command. If the value is t
(the default), the command normally just indents the current line. If
the value is nil, the command indents the current line only if
point is at the left margin or in the line’s indentation; otherwise,
it inserts a tab character. If the value is complete, the
command first tries to indent the current line, and if the line was
already indented, it calls completion-at-point to complete the
text at point (see 普通缓冲区中的补全).
If tab-always-indent is complete, whether to expand or
indent can be further customized via the tab-first-completion
variable. The following values can be used:
eolOnly complete if point is at the end of a line.
wordComplete unless the next character has word syntax.
word-or-parenComplete unless the next character has word syntax or is a parenthesis.
word-or-paren-or-punctComplete unless the next character has word syntax, or is a parenthesis, or is punctuation.
In any case, typing TAB a second time always results in completion.
Some major modes need to support embedded regions of text whose
syntax belongs to a different major mode. Examples include
literate programming source files that combine documentation and
snippets of source code, Yacc/Bison programs that include snippets of
Python or JS code, etc. To correctly indent the embedded chunks, the primary
mode needs to delegate the indentation to another mode’s indentation
engine (e.g., call js-indent-line for JS code or
python-indent-line for Python), while providing it with some
context to guide the indentation. Major modes, for their part, should
avoid calling widen in their indentation code and obey
prog-first-column.
This variable, when non-nil, holds the indentation context for
the sub-mode’s indentation engine provided by the superior major mode.
The value should be a list of the form (first-column . rest.
The members of the list have the following meaning:
The column to be used for top-level constructs. This replaces the default value of the top-level column used by the sub-mode, usually zero.
This value is currently unused.
The following convenience function should be used by major mode’s indentation engine in support of invocations as sub-modes of another major mode.
Call this function instead of using a literal value (usually, zero) of the column number for indenting top-level program constructs. The function’s value is the column number to use for top-level constructs. When no superior mode is in effect, this function returns zero.
This section describes commands that indent all the lines in the region. They return unpredictable values.
This command indents each nonblank line starting between start
(inclusive) and end (exclusive). If to-column is
nil, indent-region indents each nonblank line by calling
the current mode’s indentation function, the value of
indent-line-function.
If to-column is non-nil, it should be an integer
specifying the number of columns of indentation; then this function
gives each line exactly that much indentation, by either adding or
deleting whitespace.
If there is a fill prefix, indent-region indents each line
by making it start with the fill prefix.
The value of this variable is a function that can be used by
indent-region as a short cut. It should take two arguments, the
start and end of the region. You should design the function so
that it will produce the same results as indenting the lines of the
region one by one, but presumably faster.
If the value is nil, there is no short cut, and
indent-region actually works line by line.
A short-cut function is useful in modes such as C mode and Lisp mode,
where the indent-line-function must scan from the beginning of
the function definition: applying it to each line would be quadratic in
time. The short cut can update the scan information as it moves through
the lines indenting them; this takes linear time. In a mode where
indenting a line individually is fast, there is no need for a short cut.
indent-region with a non-nil argument to-column has
a different meaning and does not use this variable.
This function indents all lines starting between start (inclusive) and end (exclusive) sideways by count columns. This preserves the shape of the affected region, moving it as a rigid unit.
This is useful not only for indenting regions of unindented text, but also for indenting regions of formatted code. For example, if count is 3, this command adds 3 columns of indentation to every line that begins in the specified region.
If called interactively with no prefix argument, this command invokes a transient mode for adjusting indentation rigidly. See Indentation Commands in The GNU Emacs Manual.
This is like indent-rigidly, except that it doesn’t alter lines
that start within strings or comments.
In addition, it doesn’t alter a line if nochange-regexp matches at
the beginning of the line (if nochange-regexp is non-nil).
This section describes two commands that indent the current line based on the contents of previous lines.
This command inserts whitespace at point, extending to the same column as the next indent point of the previous nonblank line. An indent point is a non-whitespace character following whitespace. The next indent point is the first one at a column greater than the current column of point. For example, if point is underneath and to the left of the first non-blank character of a line of text, it moves to that column by inserting whitespace.
If the previous nonblank line has no next indent point (i.e., none at a
great enough column position), indent-relative either does
nothing (if unindented-ok is non-nil) or calls
tab-to-tab-stop. Thus, if point is underneath and to the right
of the last column of a short line of text, this command ordinarily
moves point to the next tab stop by inserting whitespace.
If first-only is non-nil, only the first indent point is
considered.
The return value of indent-relative is unpredictable.
In the following example, point is at the beginning of the second line:
This line is indented twelve spaces. ∗The quick brown fox jumped.
Evaluation of the expression (indent-relative nil) produces the
following:
This line is indented twelve spaces.
∗The quick brown fox jumped.
In this next example, point is between the ‘m’ and ‘p’ of ‘jumped’:
This line is indented twelve spaces. The quick brown fox jum∗ped.
Evaluation of the expression (indent-relative nil) produces the
following:
This line is indented twelve spaces. The quick brown fox jum ∗ped.
This command indents the current line like the previous nonblank line,
by calling indent-relative with t as the
first-only argument. The return value is unpredictable.
If the previous nonblank line has no indent points beyond the current column, this command does nothing.
This section explains the mechanism for user-specified tab stops and the mechanisms that use and set them. The name “tab stops” is used because the feature is similar to that of the tab stops on a typewriter. The feature works by inserting an appropriate number of spaces and tab characters to reach the next tab stop column; it does not affect the display of tab characters in the buffer (see Usual Display Conventions). Note that the TAB character as input uses this tab stop feature only in a few major modes, such as Text mode. See Tab Stops in The GNU Emacs Manual.
This command inserts spaces or tabs before point, up to the next tab
stop column defined by tab-stop-list.
This variable defines the tab stop columns used by tab-to-tab-stop.
It should be either nil, or a list of increasing integers,
which need not be evenly spaced. The list is implicitly
extended to infinity through repetition of the interval between the
last and penultimate elements (or tab-width if the list has
fewer than two elements). A value of nil means a tab stop
every tab-width columns.
Use M-x edit-tab-stops to edit the location of tab stops interactively.
These commands, primarily for interactive use, act based on the indentation in the text.
This command moves point to the first non-whitespace character in the current line (which is the line in which point is located).
This command moves point backward arg lines and then to the
first nonblank character on that line. If arg is omitted or
nil, it defaults to 1.
This command moves point forward arg lines and then to the first
nonblank character on that line. If arg is omitted or
nil, it defaults to 1.
The case change commands described here work on text in the current buffer. See Lisp 中的大小写转换, for case conversion functions that work on strings and characters. See 大小写转换表, for how to customize which characters are upper or lower case and how to convert them.
This function capitalizes all words in the region defined by
start and end. To capitalize means to convert each word’s
first character to upper case and convert the rest of each word to lower
case. The function returns nil.
If one end of the region is in the middle of a word, the part of the word within the region is treated as an entire word.
When capitalize-region is called interactively, start and
end are point and the mark, with the smallest first.
---------- Buffer: foo ---------- This is the contents of the 5th foo. ---------- Buffer: foo ----------
(capitalize-region 1 37) ⇒ nil ---------- Buffer: foo ---------- This Is The Contents Of The 5th Foo. ---------- Buffer: foo ----------
This function converts all of the letters in the region defined by
start and end to lower case. The function returns
nil.
When downcase-region is called interactively, start and
end are point and the mark, with the smallest first.
This function converts all of the letters in the region defined by
start and end to upper case. The function returns
nil.
When upcase-region is called interactively, start and
end are point and the mark, with the smallest first.
This function capitalizes count words after point, moving point
over as it does. To capitalize means to convert each word’s first
character to upper case and convert the rest of each word to lower case.
If count is negative, the function capitalizes the
−count previous words but does not move point. The value
is nil.
If point is in the middle of a word, the part of the word before point is ignored when moving forward. The rest is treated as an entire word.
When capitalize-word is called interactively, count is
set to the numeric prefix argument.
This function converts the count words after point to all lower
case, moving point over as it does. If count is negative, it
converts the −count previous words but does not move point.
The value is nil.
When downcase-word is called interactively, count is set
to the numeric prefix argument.
This function converts the count words after point to all upper
case, moving point over as it does. If count is negative, it
converts the −count previous words but does not move point.
The value is nil.
When upcase-word is called interactively, count is set to
the numeric prefix argument.
Each character position in a buffer or a string can have a text property list, much like the property list of a symbol (see 属性列表). The properties belong to a particular character at a particular place, such as, the letter ‘T’ at the beginning of this sentence or the first ‘o’ in ‘foo’—if the same character occurs in two different places, the two occurrences in general have different properties.
Each property has a name and a value. Both of these can be any Lisp
object, but the name is normally a symbol. Typically each property
name symbol is used for a particular purpose; for instance, the text
property face specifies the faces for displaying the character
(see Properties with Special Meanings). The usual way to access the property
list is to specify a name and ask what value corresponds to it.
If a character has a category property, we call it the
property category of the character. It should be a symbol. The
properties of the symbol serve as defaults for the properties of the
character.
Copying text between strings and buffers preserves the properties
along with the characters; this includes such diverse functions as
substring, insert, and buffer-substring. Killing
and then yanking text (see The Kill Ring) also preserves the
properties, except that some properties are handled specially and
might be removed when text is yanked; see Yanking.
The simplest way to examine text properties is to ask for the value of
a particular property of a particular character. For that, use
get-text-property. Use text-properties-at to get the
entire property list of a character. See Text Property Search Functions, for
functions to examine the properties of a number of characters at once.
These functions handle both strings and buffers. Keep in mind that positions in a string start from 0, whereas positions in a buffer start from 1. Passing a buffer other than the current buffer may be slow.
This function returns the value of the prop property of the character after position pos in object (a buffer or string). The argument object is optional and defaults to the current buffer.
If position is at the end of object, the value is
nil, but note that buffer narrowing does not affect the value.
That is, if object is a buffer or nil, and the buffer is
narrowed and position is at the end of the narrowed buffer, the
result may be non-nil.
If there is no prop property strictly speaking, but the character
has a property category that is a symbol, then get-text-property returns
the prop property of that symbol.
This function is like get-text-property, except that it checks
overlays first and then text properties. See Overlays.
The argument object may be a string, a buffer, or a window. If it is a window, then the buffer displayed in that window is used for text properties and overlays, but only the overlays active for that window are considered. If object is a buffer, then overlays in that buffer are considered first, in order of decreasing priority, followed by the text properties. If object is a string, only text properties are considered, since strings never have overlays.
This function is like get-char-property, except that it pays
attention to properties’ stickiness and overlays’ advancement settings
instead of the property of the character at (i.e., right after)
position.
This is like get-char-property, but gives extra information
about the overlay that the property value comes from.
Its value is a cons cell whose CAR is the property value, the
same value get-char-property would return with the same
arguments. Its CDR is the overlay in which the property was
found, or nil, if it was found as a text property or not found
at all.
If position is at the end of object, both the CAR and
the CDR of the value are nil.
This variable holds an alist which maps property names to a list of
alternative property names. If a character does not specify a direct
value for a property, the alternative property names are consulted in
order; the first non-nil value is used. This variable takes
precedence over default-text-properties, and category
properties take precedence over this variable.
This function returns the entire property list of the character at
position in the string or buffer object. If object is
nil, it defaults to the current buffer.
If position is at the end of object, the value is
nil, but note that buffer narrowing does not affect the value.
That is, if object is a buffer or nil, and the buffer is
narrowed and position is at the end of the narrowed buffer, the
result may be non-nil.
This variable holds a property list giving default values for text
properties. Whenever a character does not specify a value for a
property, neither directly, through a category symbol, or through
char-property-alias-alist, the value stored in this list is
used instead. Here is an example:
(setq default-text-properties '(foo 69)
char-property-alias-alist nil)
;; Make sure character 1 has no properties of its own.
(set-text-properties 1 2 nil)
;; What we get, when we ask, is the default value.
(get-text-property 1 'foo)
⇒ 69
This function returns a copy of the intervals (i.e., text properties) in object as a list of intervals. object must be a string or a buffer. Altering the structure of this list does not change the intervals in the object.
(object-intervals (propertize "foo" 'face 'bold))
⇒ ((0 3 (face bold)))
Each element in the returned list represents one interval. Each interval has three parts: The first is the start, the second is the end, and the third part is the text property itself.
The primitives for changing properties apply to a specified range of
text in a buffer or string. The function set-text-properties
(see end of section) sets the entire property list of the text in that
range; more often, it is useful to add, change, or delete just certain
properties specified by name.
Since text properties are considered part of the contents of the buffer (or string), and can affect how a buffer looks on the screen, any change in buffer text properties marks the buffer as modified. Buffer text property changes are undoable also (see Undo). Positions in a string start from 0, whereas positions in a buffer start from 1.
This function sets the prop property to value for the text
between start and end in the string or buffer object.
If object is nil, it defaults to the current buffer.
This function adds or overrides text properties for the text between
start and end in the string or buffer object. If
object is nil, it defaults to the current buffer.
The argument props specifies which properties to add. It should have the form of a property list (see 属性列表): a list whose elements include the property names followed alternately by the corresponding values.
The return value is t if the function actually changed some
property’s value; nil otherwise (if props is nil or
its values agree with those in the text).
For example, here is how to set the comment and face
properties of a range of text:
(add-text-properties start end
'(comment t face highlight))
This function deletes specified text properties from the text between
start and end in the string or buffer object. If
object is nil, it defaults to the current buffer.
The argument props specifies which properties to delete. It
should have the form of a property list (see 属性列表): a list
whose elements are property names alternating with corresponding values.
But only the names matter—the values that accompany them are ignored.
For example, here’s how to remove the face property.
(remove-text-properties start end '(face nil))
The return value is t if the function actually changed some
property’s value; nil otherwise (if props is nil or
if no character in the specified text had any of those properties).
To remove all text properties from certain text, use
set-text-properties and specify nil for the new property
list.
Like remove-text-properties except that
list-of-properties is a list of property names only, not an
alternating list of property names and values.
This function completely replaces the text property list for the text
between start and end in the string or buffer object.
If object is nil, it defaults to the current buffer.
The argument props is the new property list. It should be a list whose elements are property names alternating with corresponding values.
After set-text-properties returns, all the characters in the
specified range have identical properties.
If props is nil, the effect is to get rid of all properties
from the specified range of text. Here’s an example:
(set-text-properties start end nil)
Do not rely on the return value of this function.
This function acts on the text between start and end,
adding the face face to the face text property.
face should be a valid value for the face property
(see Properties with Special Meanings), such as a face name or an anonymous face
(see Faces).
If any text in the region already has a non-nil face property,
those face(s) are retained. This function sets the face
property to a list of faces, with face as the first element (by
default) and the pre-existing faces as the remaining elements. If the
optional argument appendp is non-nil, face is
appended to the end of the list instead. Note that in a face list,
the first occurring value for each attribute takes precedence.
For example, the following code would assign an italicized green face to the text between start and end:
(add-face-text-property start end 'italic) (add-face-text-property start end '(:foreground "red")) (add-face-text-property start end '(:foreground "green"))
The optional argument object, if non-nil, specifies a
buffer or string to act on, rather than the current buffer. If
object is a string, then start and end are
zero-based indices into the string.
The easiest way to make a string with text properties is with
propertize:
This function returns a copy of string with the text properties
properties added. These properties apply to all the characters
in the string that is returned. Here is an example that constructs a
string with a face property and a mouse-face property:
(propertize "foo" 'face 'italic
'mouse-face 'bold-italic)
⇒ #("foo" 0 3 (mouse-face bold-italic face italic))
To put different properties on various parts of a string, you can
construct each part with propertize and then combine them with
concat:
(concat
(propertize "foo" 'face 'italic
'mouse-face 'bold-italic)
" and "
(propertize "bar" 'face 'italic
'mouse-face 'bold-italic))
⇒ #("foo and bar"
0 3 (face italic mouse-face bold-italic)
3 8 nil
8 11 (face italic mouse-face bold-italic))
See Examining Buffer Contents, for the function
buffer-substring-no-properties, which copies text from the
buffer but does not copy its properties.
If you wish to add text properties to a buffer or remove them
without marking the buffer as modified, you can wrap the calls above
in the with-silent-modifications macro. See Buffer Modification.
In typical use of text properties, most of the time several or many consecutive characters have the same value for a property. Rather than writing your programs to examine characters one by one, it is much faster to process chunks of text that have the same property value.
Here are functions you can use to do this. They use eq for
comparing property values. In all cases, object defaults to the
current buffer.
For good performance, it’s very important to use the limit argument to these functions, especially the ones that search for a single property—otherwise, they may spend a long time scanning to the end of the buffer, if the property you are interested in does not change.
These functions do not move point; instead, they return a position (or
nil). Remember that a position is always between two characters;
the position returned by these functions is between two characters with
different properties.
The function scans the text forward from position pos in the string or buffer object until it finds a change in some text property, then returns the position of the change. In other words, it returns the position of the first character beyond pos whose properties are not identical to those of the character just after pos.
If limit is non-nil, then the scan ends at position
limit. If there is no property change before that point, this
function returns limit.
The value is nil if the properties remain unchanged all the way
to the end of object and limit is nil. If the value
is non-nil, it is a position greater than or equal to pos.
The value equals pos only when limit equals pos.
Here is an example of how to scan the buffer by chunks of text within which all properties are constant:
(while (not (eobp))
(let ((plist (text-properties-at (point)))
(next-change
(or (next-property-change (point) (current-buffer))
(point-max))))
Process text from point to next-change...
(goto-char next-change)))
This is like next-property-change, but scans back from pos
instead of forward. If the value is non-nil, it is a position
less than or equal to pos; it equals pos only if limit
equals pos.
The function scans text for a change in the prop property, then returns the position of the change. The scan goes forward from position pos in the string or buffer object. In other words, this function returns the position of the first character beyond pos whose prop property differs from that of the character just after pos.
If limit is non-nil, then the scan ends at position
limit. If there is no property change before that point,
next-single-property-change returns limit.
The value is nil if the property remains unchanged all the way to
the end of object and limit is nil. If the value is
non-nil, it is a position greater than or equal to pos; it
equals pos only if limit equals pos.
This is like next-single-property-change, but scans back from
pos instead of forward. If the value is non-nil, it is a
position less than or equal to pos; it equals pos only if
limit equals pos.
This is like next-property-change except that it considers
overlay properties as well as text properties, and if no change is
found before the end of the buffer, it returns the maximum buffer
position rather than nil (in this sense, it resembles the
corresponding overlay function next-overlay-change, rather than
next-property-change). There is no object operand
because this function operates only on the current buffer. It returns
the next address at which either kind of property changes.
This is like next-char-property-change, but scans back from
pos instead of forward, and returns the minimum buffer
position if no change is found.
This is like next-single-property-change except that it
considers overlay properties as well as text properties, and if no
change is found before the end of the object, it returns the
maximum valid position in object rather than nil. Unlike
next-char-property-change, this function does have an
object operand; if object is not a buffer, only
text-properties are considered.
This is like next-single-char-property-change, but scans back
from pos instead of forward, and returns the minimum valid
position in object if no change is found.
This function returns non-nil if at least one character between
start and end has a property prop whose value is
value. More precisely, it returns the position of the first such
character. Otherwise, it returns nil.
The optional fifth argument, object, specifies the string or buffer to scan. Positions are relative to object. The default for object is the current buffer.
This function returns non-nil if at least one character between
start and end does not have a property prop with value
value. More precisely, it returns the position of the first such
character. Otherwise, it returns nil.
The optional fifth argument, object, specifies the string or buffer to scan. Positions are relative to object. The default for object is the current buffer.
Search for the next region of text whose property prop is a
match for value (which defaults to nil), according to
predicate.
This function is modeled after search-forward (see Searching for Strings) and friends, in that it moves point, but it also returns a
structure that describes the match instead of returning it in
match-beginning and friends.
If the text property whose value is a match can’t be found, the
function returns nil. If it’s found, point is placed at the
end of the region that has this matching text property, and the
function returns a prop-match structure with information about
the match.
predicate can either be t (which is a synonym for
equal), nil (which means “not equal”), or a predicate
that will be called with two arguments: value and the value of
the text property prop at the buffer position that is a
candidate for a match. The function should return non-nil if
there’s a match, nil otherwise.
If not-current is non-nil, then if point is already in a
region where we have a property match, skip past that region and find
the next region instead.
The prop-match structure has the following accessor functions:
prop-match-beginning (the start of the match),
prop-match-end (the end of the match), and
prop-match-value (the value of property at the start of
the match).
In the examples below, we use a buffer whose contents is:
This is a bold and here’s bolditalic and this is the end.
That is, the “bold” words are the bold face, and the
“italic” word is in the italic face.
With point at the start:
(while (setq match (text-property-search-forward 'face 'bold t))
(push (buffer-substring (prop-match-beginning match)
(prop-match-end match))
words))
This will pick out all the words that use the bold face.
(while (setq match (text-property-search-forward 'face nil t))
(push (buffer-substring (prop-match-beginning match)
(prop-match-end match))
words))
This will pick out all the bits that have no face properties, which
will result in the list ‘("This is a " "and here's "
"and this is the end")’ (only in reverse order, since we used
push, see 修改列表变量).
(while (setq match (text-property-search-forward 'face nil nil))
(push (buffer-substring (prop-match-beginning match)
(prop-match-end match))
words))
This will pick out all the regions where face is set to
something, but this is split up into where the properties change, so
the result here will be ‘("bold" "bold" "italic")’.
For a more realistic example where you might use this, consider that
you have a buffer where certain sections represent URLs, and these are
tagged with shr-url.
(while (setq match (text-property-search-forward 'shr-url nil nil)) (push (prop-match-value match) urls))
This will give you a list of all those URLs.
This is just like text-property-search-forward, but searches
backward instead, and if a match is found, point is placed at the
beginning of the matched region instead of the end.
Here is a table of text property names that have special built-in meanings. The following sections list a few additional special property names that control filling and property inheritance. All other names have no standard meaning, and you can use them as you like.
Note: the properties composition, display,
invisible and intangible can also cause point to move to
an acceptable place, after each Emacs command. See 命令执行后的光标位置调整.
category ¶If a character has a category property, we call it the
property category of the character. It should be a symbol. The
properties of this symbol serve as defaults for the properties of the
character.
face ¶The face property controls the appearance of the character
(see Faces). The value of the property can be the following:
(keyword
value …), where each keyword is a face attribute
name and value is a value for that attribute.
(foreground-color . color-name)
or (background-color . color-name). This specifies the
foreground or background color, similar to (:foreground
color-name) or (:background color-name). This
form is supported for backward compatibility only, and should be
avoided.
(:filtered filter face-spec), that specifies the face given by face-spec,
but only if filter matches when the face is used for display.
The face-spec can use any of the forms mentioned above. The
filter should be of the form (:window param value), which matches for windows whose parameter param
is eq to value. If the variable
face-filters-always-match is non-nil, all face filters
are deemed to have matched.
Font Lock mode (see Font Lock Mode) works in most buffers by
dynamically updating the face property of characters based on
the context.
The add-face-text-property function provides a convenient way
to set this text property. See Changing Text Properties.
font-lock-face ¶This property specifies a value for the face property that Font
Lock mode should apply to the underlying text. It is one of the
fontification methods used by Font Lock mode, and is useful for
special modes that implement their own highlighting.
See 预计算高亮. When Font Lock mode is disabled,
font-lock-face has no effect.
mouse-face ¶This property is used instead of face when the mouse pointer
hovers over the text which has this property. When this happens, the
entire stretch of text that has the same mouse-face property
value, not just the character under the mouse, is highlighted.
Emacs ignores all face attributes from the mouse-face property
that alter the text size (e.g., :height, :weight, and
:slant). Those attributes are always the same as for the
unhighlighted text.
cursor-face ¶This property is similar to mouse-face, but it is used when
point (not the mouse) is inside text that has this property. The
highlighting happens only if the mode
cursor-face-highlight-mode is enabled. When the variable
cursor-face-highlight-nonselected-window is non-nil, the
text with this face is highlighted even if the window is not selected,
similarly to what highlight-nonselected-windows does for the
region (see The Mark and the Region in The GNU Emacs
Manual).
fontified ¶This property says whether the text is ready for display. If
nil, Emacs’s redisplay routine calls the functions in
fontification-functions (see Automatic Face Assignment) to prepare this
part of the buffer before it is displayed. It is used internally by
the just-in-time font locking code.
displayThis property activates various features that change the
way text is displayed. For example, it can make text appear taller
or shorter, higher or lower, wider or narrow, or replaced with an image.
See The display Property.
help-echo ¶If text has a string as its help-echo property, then when you
move the mouse onto that text, Emacs displays that string in the echo
area, or in the tooltip window (see Tooltips), after passing it
through substitute-command-keys.
If the value of the help-echo property is a function, that
function is called with three arguments, window, object and
pos and should return a help string or nil for
none. The first argument, window is the window in which
the help was found. The second, object, is the buffer, overlay or
string which had the help-echo property. The pos
argument is as follows:
help-echo
property, and pos is the position in the overlay’s buffer.
display property), pos is the position in that
string.
If the value of the help-echo property is neither a function nor
a string, it is evaluated to obtain a help string.
You can alter the way help text is displayed by setting the variable
show-help-function (see Help display).
This feature is used in the mode line and for other active text.
help-echo-inhibit-substitution ¶If the first character of a help-echo string has a
non-nil help-echo-inhibit-substitution property, then it
is displayed as-is by show-help-function, without being passed
through substitute-command-keys.
left-fringe-help ¶right-fringe-helpIf any visible text of a screen line has the left-fringe-help or
right-fringe-help text property whose value is a string, then
that string will be displayed when the mouse pointer hovers over the
corresponding line’s fringe through show-help-function
(see Help display). This is useful when used together with fringe
cursors and bitmaps (see Fringes).
keymap ¶The keymap property specifies an additional keymap for
commands. When this keymap applies, it is used for key lookup before
the minor mode keymaps and before the buffer’s local map.
See 活跃按键映射表. If the property value is a symbol, the
symbol’s function definition is used as the keymap.
The property’s value for the character before point applies if it is
non-nil and rear-sticky, and the property’s value for the
character after point applies if it is non-nil and
front-sticky. (For mouse clicks, the position of the click is used
instead of the position of point.)
local-map ¶This property works like keymap except that it specifies a
keymap to use instead of the buffer’s local map. For most
purposes (perhaps all purposes), it is better to use the keymap
property.
syntax-tableThe syntax-table property overrides what the syntax table says
about this particular character. See Syntax Properties.
read-only ¶If a character has the property read-only, then modifying that
character is not allowed. Any command that would do so gets an error,
text-read-only. If the property value is a string, that string
is used as the error message.
Insertion next to a read-only character is an error if inserting
ordinary text there would inherit the read-only property due to
stickiness. Thus, you can control permission to insert next to
read-only text by controlling the stickiness. See Stickiness of Text Properties.
Since changing properties counts as modifying the buffer, it is not
possible to remove a read-only property unless you know the
special trick: bind inhibit-read-only to a non-nil value
and then remove the property. See Read-Only Buffers.
inhibit-read-only ¶Characters that have the property inhibit-read-only can be
edited even in read-only buffers. See Read-Only Buffers.
invisible ¶A non-nil invisible property can make a character invisible
on the screen. See Invisible Text, for details.
inhibit-isearch ¶A non-nil inhibit-isearch property will make isearch
skip the text.
intangible ¶If a group of consecutive characters have equal and non-nil
intangible properties, then you cannot place point between them.
If you try to move point forward into the group, point actually moves to
the end of the group. If you try to move point backward into the group,
point actually moves to the start of the group.
If consecutive characters have unequal non-nil
intangible properties, they belong to separate groups; each
group is separately treated as described above.
When the variable inhibit-point-motion-hooks is non-nil
(as it is by default), the intangible property is ignored.
Beware: this property operates at a very low level, and affects a lot of code
in unexpected ways. So use it with extreme caution. A common misuse is to put
an intangible property on invisible text, which is actually unnecessary since
the command loop will move point outside of the invisible text at the end of
each command anyway. See 命令执行后的光标位置调整. For these reasons, this
property is obsolete; use the cursor-intangible property instead.
cursor-intangible ¶When the minor mode cursor-intangible-mode is turned on, point
is moved away from any position that has a non-nil
cursor-intangible property, just before redisplay happens.
Note that “stickiness” of the property (see Stickiness of Text Properties)
is taken into account when computing allowed cursor positions, so (for
instance) to insert a stretch of five ‘x’ characters into which
the cursor can’t enter, you should do something like:
(insert (propertize "xxxx" 'cursor-intangible t) (propertize "x" 'cursor-intangible t 'rear-nonsticky t))
When the variable cursor-sensor-inhibit is non-nil, the
cursor-intangible property and the
cursor-sensor-functions property (described below) are ignored.
field ¶Consecutive characters with the same field property constitute a
field. Some motion functions including forward-word and
beginning-of-line stop moving at a field boundary.
See Defining and Using Fields.
cursor ¶Normally, the cursor is displayed at the beginning or the end of any
overlay and text property strings that “hide” (i.e., are displayed
instead of) the current buffer position. You can instead tell Emacs
to place the cursor on any desired character of these strings by
giving that character a non-nil cursor text property.
In addition, if the value of the cursor property is an integer,
it specifies the number of buffer’s character positions, starting with
the position where the overlay or the display property begins,
for which the cursor should be displayed on that character.
Specifically, if the value of the cursor property of a
character is the number n, the cursor will be displayed on this
character for any buffer position in the range
[ovpos..ovpos+n), where ovpos is the
overlay’s starting position given by overlay-start
(see Managing Overlays), or the position where the display
text property begins in the buffer.
In other words, the string character with the cursor property
of any non-nil value is the character where to display the
cursor when the overlay or display string make point not visible on
display. The value of the property says for which buffer positions to
display the cursor there. If the value is an integer n, the
cursor is displayed there when point is anywhere between the beginning
of the overlay or display property and n positions after
that. If the value is anything else and non-nil, the cursor is
displayed there only when point is at the buffer position that is the
beginning of the display property, or at overlay-start
if that position is not visible on display. Note that an integer
value of the cursor property could mean that the cursor is
displayed on that character even when point is visible on display.
One subtlety of this property is that it doesn’t work to put this
property on a newline character that is part of a display or overlay
string. That’s because the newline doesn’t have a graphic
representation on the screen for Emacs to find when it looks for a
character on display with that cursor property.
When the buffer has many overlay strings (e.g., see before-string) that conceal some of the buffer text or
display properties that are strings, it is a good idea to use
the cursor property on these strings to cue the Emacs display
about the places where to put the cursor while traversing these
strings. This directly communicates to the display engine where the
Lisp program wants to put the cursor, or where the user would expect
the cursor, when point is located on some buffer position that is
“covered” by the display or overlay string.
pointer ¶This specifies a specific pointer shape when the mouse pointer is over this text or image. See Pointer Shape, for possible pointer shapes.
line-spacing ¶A newline can have a line-spacing text or overlay property that
controls the height of the display line ending with that newline. The
property value overrides the default frame line spacing and the buffer
local line-spacing variable. See Line Height.
line-height ¶A newline can have a line-height text or overlay property that
controls the total height of the display line ending in that newline.
See Line Height.
wrap-prefixIf a region of text has a wrap-prefix property, the prefix it
defines will be added at display time to the beginning of every
continuation line due to text wrapping (so if lines are truncated, the
wrap-prefix is never used). The property value may be a string or an
image (see Other Display Specifications), or a stretch of whitespace such as
specified by the :width or :align-to display properties
(see Specified Spaces). Note that to have its effect, the
wrap-prefix property must be set on the entire region of text,
starting from the first character of the first line of that text and up
to the last character of the last line; otherwise, breaking the text
into lines in a different way might fail to display the prefix, because
the display engine checks for this property only immediately after
continuing a line.
A wrap-prefix may also be specified for an entire buffer using the
wrap-prefix buffer-local variable (however, a
wrap-prefix text-property takes precedence over the value of
the wrap-prefix variable). See Truncation.
line-prefixIf a region of text has a line-prefix property, the prefix it
defines will be added at display time to the beginning of every
non-continuation line. The property value may be a string or an image
(see Other Display Specifications), or a stretch of whitespace such as
specified by the :width or :align-to display properties
(see Specified Spaces). Note that to have its effect, the
line-prefix property must be set on the entire region of text,
starting from the first character of the first line of that text and up
to the last character of the last line; otherwise, breaking the text
into lines in a different way might fail to display the prefix, because
the display engine checks for this property only when starting a new
line.
A line-prefix may also be specified for an entire buffer using the
line-prefix buffer-local variable (however, a
line-prefix text-property takes precedence over the value of
the line-prefix variable). See Truncation.
modification-hooks ¶If a character has the property modification-hooks, then its
value should be a list of functions; modifying that character calls
all of those functions before the actual modification. Each function
receives two arguments: the beginning and end of the part of the
buffer being modified. Note that if a particular modification hook
function appears on several characters being modified by a single
primitive, you can’t predict how many times the function will
be called.
Furthermore, insertion will not modify any existing character, so this
hook will only be run when removing some characters, replacing them
with others, or changing their text-properties.
Unlike with other similar hooks, when Emacs calls these functions,
inhibit-modification-hooks does not get bound to
non-nil. If the functions modify the buffer, you should
consider binding this variable to non-nil to prevent any buffer
changes running the change hooks. Otherwise, you must be prepared for
recursive calls. See Change Hooks.
Overlays also support the modification-hooks property, but the
details are somewhat different (see Overlay Properties).
insert-in-front-hooks ¶insert-behind-hooksThe operation of inserting text in a buffer also calls the functions
listed in the insert-in-front-hooks property of the following
character and in the insert-behind-hooks property of the
preceding character. These functions receive two arguments, the
beginning and end of the inserted text. The functions are called
after the actual insertion takes place.
When these functions are called, inhibit-modification-hooks is
bound to non-nil. If the functions modify the buffer, you
might want to bind inhibit-modification-hooks to nil, so
as to cause the change hooks to run for these modifications. However,
doing this may call your own change hook recursively, so be sure to
prepare for that.
See also Change Hooks, for other hooks that are called when you change text in a buffer.
point-entered ¶point-leftThe special properties point-entered and point-left
record hook functions that report motion of point. Each time point
moves, Emacs compares these two property values:
point-left property of the character after the old location,
and
point-entered property of the character after the new
location.
If these two values differ, each of them is called (if not nil)
with two arguments: the old value of point, and the new one.
The same comparison is made for the characters before the old and new
locations. The result may be to execute two point-left functions
(which may be the same function) and/or two point-entered
functions (which may be the same function). In any case, all the
point-left functions are called first, followed by all the
point-entered functions.
It is possible to use char-after to examine characters at various
buffer positions without moving point to those positions. Only an
actual change in the value of point runs these hook functions.
The variable inhibit-point-motion-hooks by default inhibits
running the point-left and point-entered hooks, see
Inhibit point motion hooks.
These properties are obsolete; please use
cursor-sensor-functions instead.
cursor-sensor-functions ¶This special property records a list of functions that react to cursor
motion. Each function in the list is called, just before redisplay,
with 3 arguments: the affected window, the previous known position of
the cursor, and one of the symbols entered or left,
depending on whether the cursor is entering the text that has this
property or leaving it. The functions are called only when the minor
mode cursor-sensor-mode is turned on.
When the variable cursor-sensor-inhibit is non-nil, the
cursor-sensor-functions property is ignored.
composition ¶This text property is used to display a sequence of characters as a
single glyph composed from components. But the value of the property
itself is completely internal to Emacs and should not be manipulated
directly by, for instance, put-text-property.
minibuffer-message ¶This text property tells where to display temporary messages in an
active minibuffer. Specifically, the first character of the
minibuffer text which has this property will have the temporary
message displayed before it. The default is to display temporary
messages at the end of the minibuffer text. This text property is
used by the function that is the default value of
set-message-function (see Displaying Messages in the Echo Area).
display-line-numbers-disable ¶This text property prevents display of line numbers (see display-line-numbers in The GNU Emacs Manual) for the text which has this property.
When this obsolete variable is
non-nil, point-left and point-entered hooks are
not run, and the intangible property has no effect. Do not set
this variable globally; bind it with let. Since the affected
properties are obsolete, this variable’s default value is t, to
effectively disable them.
If this variable is non-nil, it specifies
a function called to display help strings. These may be
help-echo properties, menu help strings (see 简单菜单项, see 扩展菜单项), or tool bar help strings
(see 工具栏). The specified function is called with one
argument, the help string to display, which is passed through
substitute-command-keys before being given to the function,
unless the help string has a non-nil
help-echo-inhibit-substitution property on its first character; see
文档中的按键绑定替换. See the code of Tooltip mode
(see Tooltips in The GNU Emacs Manual) for an example of a
mode that uses show-help-function.
If this variable is non-nil, face filters that specify
attributes applied only when certain conditions are met will be deemed
to match always.
These text properties affect the behavior of the fill commands. They are used for representing formatted text. See Filling, and Margins for Filling.
hardIf a newline character has this property, it is a “hard” newline.
The fill commands do not alter hard newlines and do not move words
across them. However, this property takes effect only if the
use-hard-newlines minor mode is enabled. See Hard and Soft Newlines in The GNU Emacs Manual.
right-marginThis property specifies an extra right margin for filling this part of the text.
left-marginThis property specifies an extra left margin for filling this part of the text.
justificationThis property specifies the style of justification for filling this part of the text.
Self-inserting characters, the ones that get inserted into a buffer when the user types them (see User-Level Insertion Commands), normally take on the same properties as the preceding character. This is called inheritance of properties.
By contrast, a Lisp program can do insertion with inheritance or without,
depending on the choice of insertion primitive. The ordinary text
insertion functions, such as insert, do not inherit any
properties. They insert text with precisely the properties of the
string being inserted, and no others. This is correct for programs
that copy text from one context to another—for example, into or out
of the kill ring. To insert with inheritance, use the special
primitives described in this section. Self-inserting characters
inherit properties because they work using these primitives.
When you do insertion with inheritance, which properties are inherited, and from where, depends on which properties are sticky. Insertion after a character inherits those of its properties that are rear-sticky. Insertion before a character inherits those of its properties that are front-sticky. When both sides offer different sticky values for the same property, the previous character’s value takes precedence.
By default, a text property is rear-sticky but not front-sticky; thus, the default is to inherit all the properties of the preceding character, and nothing from the following character.
You can control the stickiness of various text properties with two
specific text properties, front-sticky and rear-nonsticky,
and with the variable text-property-default-nonsticky. You can
use the variable to specify a different default for a given property.
You can use those two text properties to make any specific properties
sticky or nonsticky in any particular part of the text.
If a character’s front-sticky property is t, then all
its properties are front-sticky. If the front-sticky property is
a list, then the sticky properties of the character are those whose
names are in the list. For example, if a character has a
front-sticky property whose value is (face read-only),
then insertion before the character can inherit its face property
and its read-only property, but no others.
The rear-nonsticky property works the opposite way. Most
properties are rear-sticky by default, so the rear-nonsticky
property says which properties are not rear-sticky. If a
character’s rear-nonsticky property is t, then none of its
properties are rear-sticky. If the rear-nonsticky property is a
list, properties are rear-sticky unless their names are in the
list.
This variable holds an alist which defines the default rear-stickiness
of various text properties. Each element has the form
(property . nonstickiness), and it defines the
stickiness of a particular text property, property.
If nonstickiness is non-nil, this means that the property
property is rear-nonsticky by default. Since all properties are
front-nonsticky by default, this makes property nonsticky in both
directions by default.
The text properties front-sticky and rear-nonsticky, when
used, take precedence over the default nonstickiness specified in
text-property-default-nonsticky.
Here are the functions that insert text with inheritance of properties:
Insert the strings strings, just like the function insert,
but inherit any sticky properties from the adjoining text.
Insert the strings strings, just like the function
insert-before-markers, but inherit any sticky properties from the
adjoining text.
See Inserting Text, for the ordinary insertion functions which do not inherit.
Instead of computing text properties for all the text in the buffer, you can arrange to compute the text properties for parts of the text when and if something depends on them.
The primitive that extracts text from the buffer along with its
properties is buffer-substring. Before examining the properties,
this function runs the abnormal hook buffer-access-fontify-functions.
This variable holds a list of functions for computing text properties.
Before buffer-substring copies the text and text properties for a
portion of the buffer, it calls all the functions in this list. Each of
the functions receives two arguments that specify the range of the
buffer being accessed. (The buffer itself is always the current
buffer.)
The function buffer-substring-no-properties does not call these
functions, since it ignores text properties anyway.
In order to prevent the hook functions from being called more than
once for the same part of the buffer, you can use the variable
buffer-access-fontified-property.
If this variable’s value is non-nil, it is a symbol which is used
as a text property name. A non-nil value for that text property
means the other text properties for this character have already been
computed.
If all the characters in the range specified for buffer-substring
have a non-nil value for this property, buffer-substring
does not call the buffer-access-fontify-functions functions. It
assumes these characters already have the right text properties, and
just copies the properties they already have.
The normal way to use this feature is that the
buffer-access-fontify-functions functions add this property, as
well as others, to the characters they operate on. That way, they avoid
being called over and over for the same text.
Clickable text is text that can be clicked, with either the mouse or via a keyboard command, to produce some result. Many major modes use clickable text to implement textual hyper-links, or links for short.
The easiest way to insert and manipulate links is to use the
button package. See Buttons. In this section, we will
explain how to manually set up clickable text in a buffer, using text
properties. For simplicity, we will refer to the clickable text as a
link.
Implementing a link involves three separate steps: (1) indicating
clickability when the mouse moves over the link; (2) making RET
or mouse-2 on that link do something; and (3) setting up a
follow-link condition so that the link obeys
mouse-1-click-follows-link.
To indicate clickability, add the mouse-face text property to
the text of the link; then Emacs will highlight the link when the
mouse moves over it. In addition, you should define a tooltip or echo
area message, using the help-echo text property. See Properties with Special Meanings. For instance, here is how Dired indicates that file
names are clickable:
(if (dired-move-to-filename)
(add-text-properties
(point)
(save-excursion
(dired-move-to-end-of-filename)
(point))
'(mouse-face highlight
help-echo "mouse-2: visit this file in other window")))
To make the link clickable, bind RET and mouse-2 to commands that perform the desired action. Each command should check to see whether it was called on a link, and act accordingly. For instance, Dired’s major mode keymap binds mouse-2 to the following command:
(defun dired-mouse-find-file-other-window (event)
"In Dired, visit the file or directory name you click on."
(interactive "e")
(let ((window (posn-window (event-end event)))
(pos (posn-point (event-end event)))
file)
(if (not (windowp window))
(error "No file chosen"))
(with-current-buffer (window-buffer window)
(goto-char pos)
(setq file (dired-get-file-for-visit)))
(if (file-directory-p file)
(or (and (cdr dired-subdir-alist)
(dired-goto-subdir file))
(progn
(select-window window)
(dired-other-window file)))
(select-window window)
(find-file-other-window (file-name-sans-versions file t)))))
This command uses the functions posn-window and
posn-point to determine where the click occurred, and
dired-get-file-for-visit to determine which file to visit.
Instead of binding the mouse command in a major mode keymap, you can
bind it within the link text, using the keymap text property
(see Properties with Special Meanings). For instance:
(let ((map (make-sparse-keymap))) (define-key map [mouse-2] 'operate-this-button) (put-text-property link-start link-end 'keymap map))
With this method, you can easily define different commands for different links. Furthermore, the global definition of RET and mouse-2 remain available for the rest of the text in the buffer.
The basic Emacs command for clicking on links is mouse-2.
However, for compatibility with other graphical applications, Emacs
also recognizes mouse-1 clicks on links, provided the user
clicks on the link quickly without moving the mouse. This behavior is
controlled by the user option mouse-1-click-follows-link.
See Mouse References in The GNU Emacs Manual.
To set up the link so that it obeys
mouse-1-click-follows-link, you must either (1) apply a
follow-link text or overlay property to the link text, or (2)
bind the follow-link event to a keymap (which can be a major
mode keymap or a local keymap specified via the keymap text
property). The value of the follow-link property, or the
binding for the follow-link event, acts as a condition for
the link action. This condition tells Emacs two things: the
circumstances under which a mouse-1 click should be regarded as
occurring inside the link, and how to compute an action code
that says what to translate the mouse-1 click into. The link
action condition can be one of the following:
mouse-faceIf the condition is the symbol mouse-face, a position is inside
a link if there is a non-nil mouse-face property at that
position. The action code is always t.
For example, here is how Info mode handles mouse-1:
(keymap-set Info-mode-map "<follow-link>" 'mouse-face)
If the condition is a function, func, then a position pos
is inside a link if (func pos) evaluates to
non-nil. The value returned by func serves as the action
code.
For example, here is how pcvs enables mouse-1 to follow links on file names only:
(keymap-set map "<follow-link>"
(lambda (pos)
(eq (get-char-property pos 'face) 'cvs-filename-face)))
If the condition value is anything else, then the position is inside a link and the condition itself is the action code. Clearly, you should specify this kind of condition only when applying the condition via a text or overlay property on the link text (so that it does not apply to the entire buffer).
The action code tells mouse-1 how to follow the link:
If the action code is a string or vector, the mouse-1 event is
translated into the first element of the string or vector; i.e., the
action of the mouse-1 click is the local or global binding of
that character or symbol. Thus, if the action code is "foo",
mouse-1 translates into f. If it is [foo],
mouse-1 translates into foo.
For any other non-nil action code, the mouse-1 event is
translated into a mouse-2 event at the same position.
To define mouse-1 to activate a button defined with
define-button-type, give the button a follow-link
property. The property value should be a link action condition, as
described above. See Buttons. For example, here is how Help mode
handles mouse-1:
(define-button-type 'help-xref 'follow-link t 'action #'help-button-action)
To define mouse-1 on a widget defined with
define-widget, give the widget a :follow-link property.
The property value should be a link action condition, as described
above. For example, here is how the link widget specifies that
a mouse-1 click shall be translated to RET:
(define-widget 'link 'item "An embedded link." :button-prefix 'widget-link-prefix :button-suffix 'widget-link-suffix :follow-link "\C-m" :help-echo "Follow the link." :format "%[%t%]")
This function returns non-nil if position pos in the
current buffer is on a link. pos can also be a mouse event
location, as returned by event-start (see 访问鼠标事件).
A field is a range of consecutive characters in the buffer that are
identified by having the same value (comparing with eq) of the
field property (either a text-property or an overlay property).
This section describes special functions that are available for
operating on fields.
You specify a field with a buffer position, pos. We think of each field as containing a range of buffer positions, so the position you specify stands for the field containing that position.
When the characters before and after pos are part of the same
field, there is no doubt which field contains pos: the one those
characters both belong to. When pos is at a boundary between
fields, which field it belongs to depends on the stickiness of the
field properties of the two surrounding characters (see Stickiness of Text Properties). The field whose property would be inherited by text
inserted at pos is the field that contains pos.
There is an anomalous case where newly inserted text at pos
would not inherit the field property from either side. This
happens if the previous character’s field property is not
rear-sticky, and the following character’s field property is not
front-sticky. In this case, pos belongs to neither the preceding
field nor the following field; the field functions treat it as belonging
to an empty field whose beginning and end are both at pos.
In all of these functions, if pos is omitted or nil, the
value of point is used by default. If narrowing is in effect, then
pos should fall within the accessible portion. See Narrowing.
This function returns the beginning of the field specified by pos.
If pos is at the beginning of its field, and
escape-from-edge is non-nil, then the return value is
always the beginning of the preceding field that ends at pos,
regardless of the stickiness of the field properties around
pos.
If limit is non-nil, it is a buffer position; if the
beginning of the field is before limit, then limit will be
returned instead.
This function returns the end of the field specified by pos.
If pos is at the end of its field, and escape-from-edge is
non-nil, then the return value is always the end of the following
field that begins at pos, regardless of the stickiness of
the field properties around pos.
If limit is non-nil, it is a buffer position; if the end
of the field is after limit, then limit will be returned
instead.
This function returns the contents of the field specified by pos, as a string.
This function returns the contents of the field specified by pos, as a string, discarding text properties.
This function deletes the text of the field specified by pos.
This function constrains new-pos to the field that old-pos belongs to—in other words, it returns the position closest to new-pos that is in the same field as old-pos.
If new-pos is nil, then constrain-to-field uses
the value of point instead, and moves point to the resulting position
in addition to returning that position.
If old-pos is at the boundary of two fields, then the acceptable
final positions depend on the argument escape-from-edge. If
escape-from-edge is nil, then new-pos must be in
the field whose field property equals what new characters
inserted at old-pos would inherit. (This depends on the
stickiness of the field property for the characters before and
after old-pos.) If escape-from-edge is non-nil,
new-pos can be anywhere in the two adjacent fields.
Additionally, if two fields are separated by another field with the
special value boundary, then any point within this special
field is also considered to be on the boundary.
Commands like C-a with no argument, that normally move backward
to a specific kind of location and stay there once there, probably
should specify nil for escape-from-edge. Other motion
commands that check fields should probably pass t.
If the optional argument only-in-line is non-nil, and
constraining new-pos in the usual way would move it to a different
line, new-pos is returned unconstrained. This used in commands
that move by line, such as next-line and
beginning-of-line, so that they respect field boundaries only in
the case where they can still move to the right line.
If the optional argument inhibit-capture-property is
non-nil, and old-pos has a non-nil property of that
name, then any field boundaries are ignored.
You can cause constrain-to-field to ignore all field boundaries
(and so never constrain anything) by binding the variable
inhibit-field-text-motion to a non-nil value.
Some editors that support adding attributes to text in the buffer do so by letting the user specify intervals within the text, and adding the properties to the intervals. Those editors permit the user or the programmer to determine where individual intervals start and end. We deliberately provided a different sort of interface in Emacs Lisp to avoid certain paradoxical behavior associated with text modification.
If the actual subdivision into intervals is meaningful, that means you can distinguish between a buffer that is just one interval with a certain property, and a buffer containing the same text subdivided into two intervals, both of which have that property.
Suppose you take the buffer with just one interval and kill part of the text. The text remaining in the buffer is one interval, and the copy in the kill ring (and the undo list) becomes a separate interval. Then if you yank back the killed text, you get two intervals with the same properties. Thus, editing does not preserve the distinction between one interval and two.
Suppose we attempt to fix this problem by coalescing the two intervals when the text is inserted. That works fine if the buffer originally was a single interval. But suppose instead that we have two adjacent intervals with the same properties, and we kill the text of one interval and yank it back. The same interval-coalescence feature that rescues the other case causes trouble in this one: after yanking, we have just one interval. Once again, editing does not preserve the distinction between one interval and two.
Insertion of text at the border between intervals also raises questions that have no satisfactory answer.
However, it is easy to arrange for editing to behave consistently for questions of the form, “What are the properties of text at this buffer or string position?” So we have decided these are the only questions that make sense; we have not implemented asking questions about where intervals start or end.
In practice, you can usually use the text property search functions in place of explicit interval boundaries. You can think of them as finding the boundaries of intervals, assuming that intervals are always coalesced whenever possible. See Text Property Search Functions.
Emacs also provides explicit intervals as a presentation feature; see Overlays.
The following functions replace characters within a specified region based on their character codes.
This function replaces all occurrences of the character old-char with the character new-char in the region of the current buffer defined by start and end. Both characters must have the same length of their multibyte form.
If noundo is non-nil, then subst-char-in-region does
not record the change for undo and does not mark the buffer as modified.
This was useful for controlling the old selective display feature
(see Selective Display).
subst-char-in-region does not move point and returns
nil.
---------- Buffer: foo ---------- This is the contents of the buffer before. ---------- Buffer: foo ----------
(subst-char-in-region 1 20 ?i ?X)
⇒ nil
---------- Buffer: foo ----------
ThXs Xs the contents of the buffer before.
---------- Buffer: foo ----------
This function replaces all occurrences of the character fromchar
with tochar in string. By default, substitution occurs in
a copy of string, but if the optional argument inplace is
non-nil, the function modifies the string itself. In any
case, the function returns the resulting string.
This function applies a translation table to the characters in the buffer between positions start and end.
The translation table table is a string or a char-table;
(aref table ochar) gives the translated character
corresponding to ochar. If table is a string, any
characters with codes larger than the length of table are not
altered by the translation.
The return value of translate-region is the number of
characters that were actually changed by the translation. This does
not count characters that were mapped into themselves in the
translation table.
A register is a sort of variable used in Emacs editing that can hold a variety of different kinds of values. Each register is named by a single character. All ASCII characters and their meta variants (but with the exception of C-g) can be used to name registers. Thus, there are 255 possible registers. A register is designated in Emacs Lisp by the character that is its name.
This variable is an alist of elements of the form (name .
contents). Normally, there is one element for each Emacs
register that has been used.
The object name is a character (an integer) identifying the register.
The contents of a register can have several possible types:
A number stands for itself. If insert-register finds a number
in the register, it converts the number to decimal.
A marker represents a buffer position to jump to.
A string is text saved in the register.
A rectangle is represented by a list of strings.
(window-configuration position)This represents a window configuration to restore in one frame, and a position to jump to in the current buffer.
(frame-configuration position) ¶This represents a frame configuration to restore, and a position to jump to in the current buffer. Frame configurations are also known as framesets.
(file filename)This represents a file to visit; jumping to this value visits file filename.
(file-query filename position)This represents a file to visit and a position in it; jumping to this value visits file filename and goes to buffer position position. Restoring this type of position asks the user for confirmation first.
(buffer buffer-name)This represents a buffer; jumping to this value switches to buffer buffer-name.
The functions in this section return unpredictable values unless otherwise stated.
This function returns the contents of the register
reg, or nil if it has no contents.
This function sets the contents of register reg to value. A register can be set to any value, but the other register functions expect only certain data types. The return value is value.
This command displays what is contained in register reg.
This command inserts contents of register reg into the current buffer.
Normally, this command puts point before the inserted text, and the
mark after it. However, if the optional second argument beforep
is non-nil, it puts the mark before and point after.
When called interactively, the command defaults to putting point after text, and a prefix argument inverts this behavior.
If the register contains a rectangle, then the rectangle is inserted with its upper left corner at point. This means that text is inserted in the current line and underneath it on successive lines.
If the register contains something other than saved text (a string) or a rectangle (a list), currently useless things happen. This may be changed in the future.
This function reads and returns a register name, prompting with
prompt and possibly showing a preview of the existing registers
and their contents. The preview is shown in a temporary window, after
the delay specified by the user option register-preview-delay,
if its value and register-alist are both non-nil. The
preview is also shown if the user requests help (e.g., by typing the
help character). We recommend that all interactive commands which
read register names use this function.
This function can be used to transpose stretches of text:
This function exchanges two nonoverlapping portions of the buffer (if they overlap, the function signals an error). Arguments start1 and end1 specify the bounds of one portion and arguments start2 and end2 specify the bounds of the other portion.
Normally, transpose-regions relocates markers with the transposed
text; a marker previously positioned within one of the two transposed
portions moves along with that portion, thus remaining between the same
two characters in their new position. However, if leave-markers
is non-nil, transpose-regions does not do this—it leaves
all markers unrelocated.
You can use the following function to replace the text of one buffer with the text of another buffer:
This function replaces the accessible portion of the current buffer
with the accessible portion of the buffer source. source
may either be a buffer object or the name of a buffer. When
replace-buffer-contents succeeds, the text of the accessible
portion of the current buffer will be equal to the text of the
accessible portion of the source buffer.
This function attempts to keep point, markers, text properties, and
overlays in the current buffer intact. One potential case where this
behavior is useful is external code formatting programs: they
typically write the reformatted text into a temporary buffer or file,
and using delete-region and insert-buffer-substring
would destroy these properties. However, the latter combination is
typically faster (See Deleting Text, and Inserting Text).
For its working, replace-buffer-contents needs to compare the
contents of the original buffer with that of source which is a
costly operation if the buffers are huge and there is a high number of
differences between them. In order to keep
replace-buffer-contents’s runtime in bounds, it has two
optional arguments.
max-secs defines a hard boundary in terms of seconds. If given
and exceeded, it will fall back to delete-region and
insert-buffer-substring.
max-costs defines the quality of the difference computation. If the actual costs exceed this limit, heuristics are used to provide a faster but suboptimal solution. The default value is 1000000.
replace-buffer-contents returns t if a non-destructive
replacement could be performed. Otherwise, i.e., if max-secs
was exceeded, it returns nil.
This function replaces the region between beg and end using the given replace-fn. The function replace-fn is run in the current buffer narrowed to the specified region and it should return either a string or a buffer replacing the region.
The replacement is performed using replace-buffer-contents (see
above) which also describes the max-secs and max-costs
arguments and the return value.
Note: If the replacement is a string, it will be placed in a temporary
buffer so that replace-buffer-contents can operate on it.
Therefore, if you already have the replacement in a buffer, it makes
no sense to convert it to a string using buffer-substring or
similar.
When auto-compression-mode is enabled, Emacs automatically
uncompresses compressed files when you visit them, and automatically
recompresses them if you alter and save them. See Compressed
Files in The GNU Emacs Manual.
The above feature works by calling an external executable (e.g.,
gzip). Emacs can also be compiled with support for built-in
decompression using the zlib library, which is faster than calling an
external program.
This function returns non-nil if built-in zlib decompression is
available.
This function decompresses the region between start and
end, using built-in zlib decompression. The region should
contain data that were compressed with gzip or zlib. On success, the
function replaces the contents of the region with the decompressed
data. If allow-partial is nil or omitted, then on
failure, the function leaves the region unchanged and returns
nil. Otherwise, it returns the number of bytes that were not
decompressed and replaces the region text by whatever data was
successfully decompressed. This function can be called only in
unibyte buffers.
Base 64 code is used in email to encode a sequence of 8-bit bytes as a longer sequence of ASCII graphic characters. It is defined in Internet RFC242045 and also in RFC 4648. This section describes the functions for converting to and from this code.
This function converts the region from beg to end into base 64 code. It returns the length of the encoded text. An error is signaled if a character in the region is multibyte, i.e., in a multibyte buffer the region must contain only ASCII characters or raw bytes.
Normally, this function inserts newline characters into the encoded
text, to avoid overlong lines. However, if the optional argument
no-line-break is non-nil, these newlines are not added, so
the output is just one long line.
This function is like base64-encode-region, but it implements
the URL variant of base 64 encoding, per RFC 4648, and it doesn’t
insert newline characters into the encoded text, so the output is
just one long line.
If the optional argument no-pad is non-nil then this
function doesn’t generate the padding (=).
This function converts the string string into base 64 code. It
returns a string containing the encoded text. As for
base64-encode-region, an error is signaled if a character in the
string is multibyte.
Normally, this function inserts newline characters into the encoded
text, to avoid overlong lines. However, if the optional argument
no-line-break is non-nil, these newlines are not added, so
the result string is just one long line.
Like base64-encode-string, but generates the URL variant of
base 64, and doesn’t insert newline characters into the encoded text,
so the result is just one long line.
If the optional argument no-pad is non-nil then this
function doesn’t generate the padding.
This function converts the region from beg to end from base 64 code into the corresponding decoded text. It returns the length of the decoded text.
The decoding functions ignore newline characters in the encoded text.
If optional argument base64url is non-nil, then padding
is optional, and the URL variant of base 64 encoding is used.
If optional argument ignore-invalid is non-nil, then any
unrecognized characters are ignored.
This function converts the string string from base 64 code into the corresponding decoded text. It returns a unibyte string containing the decoded text.
The decoding functions ignore newline characters in the encoded text.
If optional argument base64url is non-nil, then padding
is optional, and the URL variant of base 64 encoding is used.
If optional argument ignore-invalid is non-nil, then any
unrecognized characters are ignored.
Emacs has built-in support for computing cryptographic hashes. A cryptographic hash, or checksum, is a digital fingerprint of a piece of data (e.g., a block of text) which can be used to check that you have an unaltered copy of that data.
Emacs supports several common cryptographic hash algorithms: MD5,
SHA-1, SHA-2, SHA-224, SHA-256, SHA-384 and SHA-512. MD5 is the
oldest of these algorithms, and is commonly used in message
digests to check the integrity of messages transmitted over a
network. MD5 and SHA-1 are not collision resistant (i.e., it is
possible to deliberately design different pieces of data which have
the same MD5 or SHA-1 hash), so you should not use them for anything
security-related. For security-related applications you should use
the other hash types, such as SHA-2 (e.g., sha256 or
sha512).
This function returns a list of symbols representing algorithms that
secure-hash can use.
This function returns a hash for object. The argument
algorithm is a symbol stating which hash to compute: one of
md5, sha1, sha224, sha256, sha384
or sha512. The argument object should be a buffer or a
string.
The optional arguments start and end are character
positions specifying the portion of object to compute the
message digest for. If they are nil or omitted, the hash is
computed for the whole of object.
If the argument binary is omitted or nil, the function
returns the text form of the hash, as an ordinary Lisp string.
If binary is non-nil, it returns the hash in binary
form, as a sequence of bytes stored in a unibyte string. The length
of the returned string depends on algorithm:
md5: 32 characters (16 bytes if binary is
non-nil).
sha1: 40 characters (20 bytes if binary is
non-nil).
sha224: 56 characters (28 bytes if binary is
non-nil).
sha256: 64 characters (32 bytes if binary is
non-nil).
sha384: 96 characters (48 bytes if binary is
non-nil).
sha512: 128 characters (64 bytes if binary is
non-nil).
This function does not compute the hash directly from the internal representation of object’s text (see Text Representations). Instead, it encodes the text using a coding system (see Coding Systems), and computes the hash from that encoded text. If object is a buffer, the coding system used is the one which would be chosen by default for writing the text of that buffer into a file. If object is a string, the user’s preferred coding system is used (see Recognize Coding in GNU Emacs Manual).
This function returns an MD5 hash. It is semi-obsolete, since for
most purposes it is equivalent to calling secure-hash with
md5 as the algorithm argument. The object,
start and end arguments have the same meanings as in
secure-hash. The function returns a 32-character string.
If coding-system is non-nil, it specifies a coding system
to use to encode the text; if omitted or nil, the default
coding system is used, like in secure-hash.
Normally, md5 signals an error if the text can’t be encoded
using the specified or chosen coding system. However, if
noerror is non-nil, it silently uses raw-text
coding instead.
Return a hash of buffer-or-name. If nil, this defaults
to the current buffer. As opposed to secure-hash, this
function computes the hash based on the internal representation of the
buffer, disregarding any coding systems. It’s therefore only useful
when comparing two buffers running in the same Emacs, and is not
guaranteed to return the same hash between different Emacs versions.
It should be somewhat more efficient on larger buffers than
secure-hash is, and should not allocate more memory.
This function is equivalent to calling secure-hash like this:
(secure-hash 'sha1 object start end binary)
It returns a 40-character string if binary is nil, or a
20-byte unibyte string otherwise.
Emacs can display text from many external sources, like email and Web sites. Attackers may attempt to confuse the user reading this text by using obfuscated URLs or email addresses, and tricking the user into visiting a web page they didn’t intend to visit, or sending an email to the wrong address.
This usually involves using characters from scripts that visually look like ASCII characters (i.e., are homoglyphs), but there are also other techniques used, like using bidirectional overrides, or having an HTML link text that says one thing, while the underlying URL points somewhere else.
To help identify these suspicious text strings, Emacs provides a library to do a number of checks on text. (See UTS #39: Unicode Security Mechanisms for the rationale behind the checks that are available and more details about them.) Packages that present data that might be suspicious should use this library to flag suspicious text on display.
This function is the high-level interface function that packages
should use. It respects the textsec-check user option, which
allows the user to disable the checks.
This function checks object (whose data type depends on type) to see if it looks suspicious when interpreted as a thing of type. The available types and the corresponding object data types are:
domainCheck whether a domain (e.g., ‘www.gnu.org’ looks suspicious. object should be a string, the domain name.
urlCheck whether an URL (e.g., ‘http://gnu.org/foo/bar’) looks suspicious. object should be a string, the URL to check.
linkCheck whether an HTML link (e.g., ‘<a
href='http://gnu.org'>fsf.org</a>’ looks suspicious. In this case,
object should be a cons cell where the car is the
URL string, and the cdr is the link text. The link
is deemed suspicious if the link text contains a domain name, and that
domain name points to something other than the URL.
email-addressCheck whether an email address (e.g., ‘[email protected]’) looks suspicious. object should be a string.
local-addressCheck whether the local part of an email address (the bit before the ‘@’ sign) looks suspicious. object should be a string.
nameCheck whether a name (used in an email address header) looks suspicious. object should be a string.
email-address-headerCheck whether a full RFC2822 email address header (e.g., ‘=?utf-8?Q?=C3=81?= <[email protected]>’) looks suspicious. object should be a string.
If object is suspicious, this function returns a string that
explains why it is suspicious. If object is not suspicious, the
function returns nil.
If the text is suspicious, the application should mark the suspicious
text with the textsec-suspicious face, and make the explanation
returned by textsec-suspicious-p available to the user in some way
(for example, in a tooltip). The application might also prompt the
user for confirmation before taking any action on a suspicious string
(like sending an email to a suspicious email address).
If compiled with GnuTLS, Emacs offers built-in cryptographic support. Following the GnuTLS API terminology, the available tools are digests, MACs, symmetric ciphers, and AEAD ciphers.
The terms used herein, such as IV (Initialization Vector), require some familiarity with cryptography and will not be defined in detail. Please consult https://www.gnutls.org/ for specific documentation which may help you understand the terminology and structure of the GnuTLS library.
The inputs to GnuTLS cryptographic functions can be specified in several ways, both as primitive Emacs Lisp types or as lists.
The list form is currently similar to how md5 and
secure-hash operate.
bufferSimply passing a buffer as input means the whole buffer should be used.
stringA string as input will be used directly. It may be modified by the function (unlike most other Emacs Lisp functions) to reduce the chance of exposing sensitive data after the function does its work.
(buffer-or-string start end coding-system noerror)This specifies a buffer or a string as described above, but an optional range can be specified with start and end.
In addition an optional coding-system can be specified if needed.
The last optional item, noerror, overrides the normal error when
the text can’t be encoded using the specified or chosen coding system.
When noerror is non-nil, this function silently uses
raw-text coding instead.
(iv-auto length)This generates a random IV (Initialization Vector) of the specified length and passes it to the function. This ensures that the IV is unpredictable and unlikely to be reused in the same session.
This function returns the alist of the GnuTLS digest algorithms.
Each entry has a key which represents the algorithm, followed by a
plist with internal details about the algorithm. The plist will have
:type gnutls-digest-algorithm and also will have the key
:digest-algorithm-length 64 to indicate the size, in bytes, of
the resulting digest.
There is a name parallel between GnuTLS MAC and digest algorithms but they are separate things internally and should not be mixed.
The digest-method can be the whole plist from
gnutls-digests, or just the symbol key, or a string with the
name of that symbol.
The input can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs).
This function returns nil on error, and signals a Lisp error if
the digest-method or input are invalid. On success, it
returns a list of a binary string (the output) and the IV used.
This function returns the alist of the GnuTLS MAC algorithms.
Each entry has a key which represents the algorithm, followed by a
plist with internal details about the algorithm. The plist will have
:type gnutls-mac-algorithm and also will have the keys
:mac-algorithm-length :mac-algorithm-keysize
:mac-algorithm-noncesize to indicate the size, in bytes, of the
resulting hash, the key, and the nonce respectively.
The nonce is currently unused and only some MACs support it.
There is a name parallel between GnuTLS MAC and digest algorithms but they are separate things internally and should not be mixed.
The hash-method can be the whole plist from
gnutls-macs, or just the symbol key, or a string with the
name of that symbol.
The key can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs). The key will be wiped after use if it’s a string.
The input can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs).
This function returns nil on error, and signals a Lisp error if
the hash-method or key or input are invalid.
On success, it returns a list of a binary string (the output) and the IV used.
This function returns the alist of the GnuTLS ciphers.
Each entry has a key which represents the cipher, followed by a plist
with internal details about the algorithm. The plist will have
:type gnutls-symmetric-cipher and also will have the keys
:cipher-aead-capable set to nil or t to indicate
AEAD capability; and :cipher-tagsize :cipher-blocksize
:cipher-keysize :cipher-ivsize to indicate the size, in
bytes, of the tag, block size of the resulting data, the key, and the
IV respectively.
The cipher can be the whole plist from
gnutls-ciphers, or just the symbol key, or a string with the
name of that symbol.
The key can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs). The key will be wiped after use if it’s a string.
The iv and input and the optional aead_auth can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs).
aead_auth is only checked with AEAD ciphers, that is, ciphers whose
plist has :cipher-aead-capable t. Otherwise it’s ignored.
This function returns nil on error, and signals a Lisp error if
the cipher or key, iv, or input are invalid,
or if aead_auth was specified with an AEAD cipher and was
invalid.
On success, it returns a list of a binary string (the output) and the IV used.
The cipher can be the whole plist from
gnutls-ciphers, or just the symbol key, or a string with the
name of that symbol.
The key can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs). The key will be wiped after use if it’s a string.
The iv and input and the optional aead_auth can be specified as a buffer or string or in other ways (see Format of GnuTLS Cryptography Inputs).
aead_auth is only checked with AEAD ciphers, that is, ciphers whose
plist has :cipher-aead-capable t. Otherwise it’s ignored.
This function returns nil on decryption error, and signals a
Lisp error if the cipher or key, iv, or input
are invalid, or if aead_auth was specified with an AEAD cipher
and was invalid.
On success, it returns a list of a binary string (the output) and the IV used.
Emacs can be compiled with built-in support for accessing SQLite databases. This section describes the facilities available for accessing SQLite databases from Lisp programs.
The function returns non-nil if built-in SQLite support is
available in this Emacs session.
When SQLite support is available, the following functions can be used.
This function opens file as an SQLite database file. If
file doesn’t exist, a new database will be created and stored in
that file. If file is omitted or nil, a new in-memory
database is created instead.
The return value is a database object that can be used as the argument to most of the subsequent functions described below.
This predicate returns non-nil if object is an SQLite
database object. The database object returned by the
sqlite-open function satisfies this predicate.
Close the database db. It’s usually not necessary to call this function explicitly—the database will automatically be closed if Emacs shuts down or the database object is garbage collected.
Execute the SQL statement. For instance:
(sqlite-execute db "insert into foo values ('bar', 2)")
If the optional values parameter is present, it should be either a list or a vector of values to bind while executing the statement. For instance:
(sqlite-execute db "insert into foo values (?, ?)" '("bar" 2))
This has exactly the same effect as the previous example, but is more efficient and safer (because it doesn’t involve any string parsing or interpolation).
sqlite-execute usually returns the number of affected rows.
For instance, an ‘insert’ statement will typically return
‘1’, whereas an ‘update’ statement may return zero or a
higher number. However, when using SQL statements like
‘insert into … returning …’ and the like, the values
specified by ‘returning …’ will be returned instead.
Strings in SQLite are, by default, stored as utf-8, and
selecting a text column will decode the string using that charset.
Selecting a blob column will return the raw data without any decoding
(i.e., it will return a unibyte string containing the bytes as stored
in the database). Inserting binary data into blob columns, however,
requires some care, as sqlite-execute will, by default,
interpret all strings as utf-8.
So if you have, for instance, GIF data in a unibyte string
called gif, you have to mark it specially to let
sqlite-execute know this:
(put-text-property 0 1 'coding-system 'binary gif) (sqlite-execute db "insert into foo values (?, ?)" (list gif 2))
Execute the SQL statements. statements is a string containing 0 or more SQL statements. This command might be useful when a Lisp program needs to execute multiple Data Definition Language (DDL) statements in one go.
Select some data from db and return them. For instance:
(sqlite-select db "select * from foo where key = 2")
⇒ (("bar" 2))
As with the sqlite-execute, you can optionally pass in a list
or a vector of values that will be bound before executing the select:
(sqlite-select db "select * from foo where key = ?" [2])
⇒ (("bar" 2))
This is usually more efficient and safer than the method used by the previous example.
By default, this function returns a list of matching rows, where each
row is a list of column values. If return-type is full,
the names of the columns (as a list of strings) will be returned as
the first element in the return value.
If return-type is set, this function will return a
statement object instead. This object can be examined by using
the sqlite-next, sqlite-columns and sqlite-more-p
functions. If the result set is small, it’s often more convenient to
just return the data directly, but if the result set is large (or if
you won’t be using all the data from the set), using the set
method will allocate a lot less memory, and is therefore more
memory-efficient.
This function returns the next row in the result set statement,
typically an object returned by sqlite-select.
(sqlite-next stmt)
⇒ ("bar" 2)
This function returns the column names of the result set
statement, typically an object returned by sqlite-select.
(sqlite-columns stmt)
⇒ ("name" "issue")
This predicate says whether there is more data to be fetched from the
result set statement, typically an object returned by
sqlite-select.
If statement is not going to be used any more, calling this function will free the resources used by statement. This is usually not necessary—when the statement object is garbage-collected, Emacs will automatically free its resources.
Start a transaction in db. When in a transaction, other readers
of the database won’t access the results until the transaction has
been committed by sqlite-commit.
End a transaction in db and write the data out to its file.
End a transaction in db and discard any changes that have been made by the transaction.
Like progn (see 顺序执行), but executes body with a
transaction held, and commits the transaction at the end if body
completes normally. If body signals an error, or committing the
transaction fails, the changes in db performed by body are
rolled back. The macro returns the value of body if it
completes normally and commit succeeds.
Execute pragma in db. A pragma is usually a command that affects the database overall, instead of any particular table. For instance, to make SQLite automatically garbage collect data that’s no longer needed, you can say:
(sqlite-pragma db "auto_vacuum = FULL")
This function returns non-nil on success and nil if the
pragma failed. Many pragmas can only be issued when the database is
brand new and empty.
Load the named extension module into the database db. Extensions are usually shared-library files; on GNU and Unix systems, they have the .so file-name extension.
Return a string denoting the version of the SQLite library in use.
If you wish to list the contents of an SQLite file, you can use the
sqlite-mode-open-file command. This will pop to a buffer using
sqlite-mode, which allows you to examine (and alter) the
contents of an SQLite database.
Emacs can be compiled with built-in libxml2 support.
This function returns non-nil if built-in libxml2 support is
available in this Emacs session.
When libxml2 support is available, the following functions can be used to parse HTML or XML text into Lisp object trees.
This function parses the text between start and end as HTML, and returns a list representing the HTML parse tree. It attempts to handle real-world HTML by robustly coping with syntax mistakes.
If start or end are nil, they default to the values
from point-min and point-max, respectively.
The optional argument base-url, if non-nil, should be
used for warnings and errors reported by the libxml2 library,
but Emacs currently calls the library with errors and warnings
disabled, so this argument is not used.
If the optional argument discard-comments is non-nil,
any top-level comment is discarded. (This argument is obsolete and
will be removed in future Emacs versions. To remove comments, use the
xml-remove-comments utility function on the data before you
call the parsing function.)
In the parse tree, each HTML node is represented by a list in which the first element is a symbol representing the node name, the second element is an alist of node attributes, and the remaining elements are the subnodes.
The following example demonstrates this. Given this (malformed) HTML document:
<html><head></head><body width=101><div class=thing>Foo<div>Yes
A call to libxml-parse-html-region returns this DOM
(document object model):
(html nil
(head nil)
(body ((width . "101"))
(div ((class . "thing"))
"Foo"
(div nil
"Yes"))))
This function renders the parsed HTML in dom into the current
buffer. The argument dom should be a list as generated by
libxml-parse-html-region. This function is, e.g., used by
EWW in The Emacs Web Wowser Manual.
This function is the same as libxml-parse-html-region, except
that it parses the text as XML rather than HTML (so it is stricter
about syntax).
The DOM returned by libxml-parse-html-region (and
the other XML parsing functions) is a tree structure where
each node has a node name (called a tag), and optional key/value
attribute list, and then a list of child nodes. The child
nodes are either strings or DOM objects.
(body ((width . "101")) (div ((class . "thing")) "Foo" (div nil "Yes")))
This function creates a DOM node of type tag. If given, attributes should be a key/value pair list. If given, children should be DOM nodes.
The following functions can be used to work with this structure. Each function takes a DOM node, or a list of nodes. In the latter case, only the first node in the list is used.
Simple accessors:
dom-tag nodeReturn the tag (also called “node name”) of the node.
dom-attr node attributeReturn the value of attribute in the node. A common usage would be:
(dom-attr img 'href) => "https://fsf.org/logo.png"
dom-children nodeReturn all the children of the node.
dom-non-text-children nodeReturn all the non-string children of the node.
dom-attributes nodeReturn the key/value pair list of attributes of the node.
dom-text nodeReturn all the textual elements of the node as a concatenated string.
dom-texts nodeReturn all the textual elements of the node, as well as the textual elements of all the children of the node, recursively, as a concatenated string. This function also takes an optional separator to be inserted between the textual elements.
dom-parent dom nodeReturn the parent of node in dom.
dom-remove dom nodeRemove node from dom.
The following are functions for altering the DOM.
dom-set-attribute node attribute valueSet the attribute of the node to value.
dom-remove-attribute node attributeRemove attribute from node.
dom-append-child node childAppend child as the last child of node.
dom-add-child-before node child beforeAdd child to node’s child list before the before
node. If before is nil, make child the first child.
dom-set-attributes node attributesReplace all the attributes of the node with a new key/value list.
The following are functions for searching for elements in the DOM. They all return lists of matching nodes.
dom-by-tag dom tagReturn all nodes in dom that are of type tag. A typical use would be:
(dom-by-tag dom 'td) => '((td ...) (td ...) (td ...))
dom-by-class dom matchReturn all nodes in dom that have class names that match match, which is a regular expression.
dom-by-style dom styleReturn all nodes in dom that have styles that match match, which is a regular expression.
dom-by-id dom styleReturn all nodes in dom that have IDs that match match, which is a regular expression.
dom-search dom predicateReturn all nodes in dom where predicate returns a
non-nil value. predicate is called with the node to be
tested as its parameter.
dom-strings domReturn all strings in dom.
Utility functions:
dom-pp dom &optional remove-emptyPretty-print dom at point. If remove-empty, don’t print textual nodes that just contain white-space.
dom-print dom &optional pretty xmlPrint dom at point. If xml is non-nil, print as
XML; otherwise, print as HTML. If pretty is
non-nil, indent the HTML/XML logically.
The Emacs JSON (JavaScript Object Notation) support provides several functions to convert between Lisp objects and JSON values. Any JSON value can be converted to a Lisp object, but not vice versa. Specifically:
true, null, false.
true is represented by the symbol t. By default, the
remaining two are represented, respectively, by the symbols
:null and :false.
assq.
Note that nil, being both a valid alist and a valid plist,
represents {}, the empty JSON object; not null,
false, or an empty array, all of which are different JSON
values.
If some Lisp object can’t be represented in JSON, the serialization
functions will signal an error of type wrong-type-argument.
The parsing functions can also signal the following errors:
json-unavailableSignaled when the parsing library isn’t available.
json-end-of-fileSignaled when encountering a premature end of the input text.
json-trailing-contentSignaled when encountering unexpected input after the first JSON object parsed.
json-parse-errorSignaled when encountering invalid JSON syntax.
Top-level values and the subobjects within these top-level values can be serialized to JSON. Likewise, the parsing functions will return any of the possible types described above.
This function returns a new Lisp unibyte string which contains the JSON representation of object. The argument args is a list of keyword/argument pairs. The following keywords are accepted:
:null-objectThe value decides which Lisp object to use to represent the JSON
keyword null. It defaults to the symbol :null.
:false-objectThe value decides which Lisp object to use to represent the JSON
keyword false. It defaults to the symbol :false.
This function inserts the JSON representation of object into the
current buffer before point. The argument args are interpreted
as in json-serialize.
This function parses the JSON value in string, which must be a
Lisp string. If string doesn’t contain a valid JSON object,
this function signals the json-parse-error error.
The argument args is a list of keyword/argument pairs. The following keywords are accepted:
:object-typeThe value decides which Lisp object to use for representing the
key-value mappings of a JSON object. It can be either
hash-table, the default, to make hashtables with strings as
keys; alist to use alists with symbols as keys; or plist
to use plists with keyword symbols as keys.
:array-typeThe value decides which Lisp object to use for representing a JSON
array. It can be either array, the default, to use Lisp
arrays; or list to use lists.
:null-objectThe value decides which Lisp object to use to represent the JSON
keyword null. It defaults to the symbol :null.
:false-objectThe value decides which Lisp object to use to represent the JSON
keyword false. It defaults to the symbol :false.
This function reads the next JSON value from the current buffer,
starting at point. It moves point to the position immediately after
the value if contains a valid JSON object; otherwise it signals the
json-parse-error error and doesn’t move point. The arguments
args are interpreted as in json-parse-string.
The jsonrpc library implements the JSONRPC
specification, version 2.0, as it is described in
https://www.jsonrpc.org/. As the name suggests, JSONRPC is a
generic Remote Procedure Call protocol designed around
JSON objects, which you can convert to and from Lisp objects
(see Parsing and generating JSON values).
Quoting from the spec, JSONRPC "is transport agnostic in that the concepts can be used within the same process, over sockets, over http, or in many various message passing environments."
To model this agnosticism, the jsonrpc library uses objects of
a jsonrpc-connection class, which represent a connection to a
remote JSON endpoint (for details on Emacs’s object system,
see EIEIO in EIEIO). In modern object-oriented parlance,
this class is “abstract”, i.e. the actual class of a useful
connection object is always a subclass of jsonrpc-connection.
Nevertheless, we can define two distinct APIs around the
jsonrpc-connection class:
In this scenario, a new aspiring JSONRPC-based application selects a
concrete subclass of jsonrpc-connection that provides the
transport for the JSONRPC messages to be exchanged between endpoints.
The application creates objects of that subclass using
make-instance. To initiate a contact to a remote endpoint, the
application passes this object to the functions such as
jsonrpc-notify, jsonrpc-request, or
jsonrpc-async-request.
For handling remotely initiated contacts, which generally come in
asynchronously, the make-instance instantiation should
initialize it the :request-dispatcher and
:notification-dispatcher EIEIO keyword arguments. These are
both functions of 3 arguments: the connection object; a symbol naming
the JSONRPC method invoked remotely; and a JSONRPC params
object.
The function passed as :request-dispatcher is responsible for
handling the remote endpoint’s requests, which expect a reply from the
local endpoint (in this case, the application you’re building).
Inside that function, you may either return locally (a regular return)
or non-locally (throw an error). Both exits from the request
dispatcher cause a reply to the remote endpoint’s request to be sent
through the transport.
A regular return determines a success response, and the return value
must be a Lisp object that can be serialized as JSON (see Parsing and generating JSON values). The result is forwarded to the server as the JSONRPC
result object. A non-local return, achieved by calling the
function jsonrpc-error, causes an error response to be sent to
the server. The details of the accompanying JSONRPC error
object are filled out with whatever was passed to
jsonrpc-error. A non-local return triggered by an unexpected
error of any other type also causes an error response to be sent
(unless you have set debug-on-error, in which case this calls
the Lisp debugger, see 发生错误时进入调试器).
It’s possible to use the jsonrpc library to build applications
based on transport protocols that can be described as
“quasi-JSONRPC”. These are similar, but not quite identical to
JSONRPC, such as the DAP (Debug
Adapter Protocol). These protocols also define request, response and
notification messages but the format is not quite the same as JSONRPC.
The generic functions jsonrpc-convert-to-endpoint and
jsonrpc-convert-from-endpoint can be customized for converting
between the internal representation of JSONRPC and whatever the
endpoint accepts (see 泛型函数).
In this scenario, jsonrpc-connection is sub-classed to implement
a different underlying transport strategy (for details on how to
subclass, see Inheritance.). Users of the
application-building interface can then instantiate objects of this
concrete class (using the make-instance function) and connect
to JSONRPC endpoints using that strategy. See Process-based JSONRPC connections for a built-in transport implementation.
This API has mandatory and optional parts.
To allow its users to initiate JSONRPC contacts (notifications or
requests) or reply to endpoint requests, the new transport
implementation must equip the jsonrpc-connection-send generic
function with a specialization for the new subclass
(see 泛型函数). This generic function is called
automatically by primitives such as jsonrpc-request and
jsonrpc-notify. The specialization should ensure that the
message described in the argument list is sent through whatever
underlying communication mechanism (a.k.a. “wire”) is used by the
new transport to talk to endpoints. This “wire” may be a network
socket, a serial interface, an HTTP connection, etc.
Likewise, for handling the three types of remote contacts (requests,
notifications, and responses to local requests), the transport
implementation must arrange for the function
jsonrpc-connection-receive to be called from Elisp after
noticing some data on the “wire” that can be used to craft a JSONRPC
(or quasi-JSONRPC) message.
Finally, and optionally, the jsonrpc-connection subclass should
add specializations to the jsonrpc-shutdown and
jsonrpc-running-p generic functions if these concepts apply to
the transport. The specialization of jsonrpc-shutdown should
ensure the release of any system resources (e.g. processes, timers,
etc.) used to listen for messages on the wire. The specialization of
jsonrpc-running-p should tell if these resources are still
active or have already been released (via jsonrpc-shutdown or
otherwise).
For convenience, the jsonrpc library comes with a built-in
jsonrpc-process-connection transport implementation that can
talk to local subprocesses (using the standard input and standard
output); or TCP hosts (using sockets); or any other remote endpoint
that Emacs’s process object can represent (see Processes).
Using this transport, the JSONRPC messages are encoded on the wire as plain text and prefaced by some basic HTTP-style enveloping headers, such as “Content-Length”.
For an example of an application using this transport scheme on top of JSONRPC, see the Language Server Protocol.
Along with the mandatory :request-dispatcher and
:notification-dispatcher initargs, users of the
jsonrpc-process-connection class should pass the following
initargs as keyword-value pairs to make-instance:
:processValue must be a live process object or a function of no arguments producing one such object. If passed a process object, the object is expected to contain a pre-established connection; otherwise, the function is called immediately after the object is made.
:on-shutdownValue must be a function of a single argument, the
jsonrpc-process-connection object. The function is called
after the underlying process object has been deleted (either
deliberately by jsonrpc-shutdown, or unexpectedly, because of
some external cause).
JSONRPC JSON objects are exchanged as Lisp plists (see 属性列表): JSON-compatible plists are handed to the dispatcher functions
and, likewise, JSON-compatible plists should be given to
jsonrpc-notify, jsonrpc-request, and
jsonrpc-async-request.
To facilitate handling plists, this library makes liberal use of
cl-lib library (see cl-lib in Common Lisp Extensions
for GNU Emacs Lisp) and suggests (but doesn’t force) its clients to
do the same. A macro jsonrpc-lambda can be used to create a
lambda for destructuring a JSON-object like in this example:
(jsonrpc-async-request
myproc :frobnicate `(:foo "trix")
:success-fn (jsonrpc-lambda (&key bar baz &allow-other-keys)
(message "Server replied back with %s and %s!"
bar baz))
:error-fn (jsonrpc-lambda (&key code message _data)
(message "Sadly, server reports %s: %s"
code message)))
In many RPC situations, synchronization between the two communicating endpoints is a matter of correctly designing the RPC application: when synchronization is needed, requests (which are blocking) should be used; when it isn’t, notifications should suffice. However, when Emacs acts as one of these endpoints, asynchronous events (e.g., timer- or process-related) may be triggered while there is still uncertainty about the state of the remote endpoint. Furthermore, acting on these events may only sometimes demand synchronization, depending on the event’s specific nature.
The :deferred keyword argument to jsonrpc-request and
jsonrpc-async-request is designed to let the caller indicate
that the specific request needs synchronization and its actual
issuance may be delayed to the future, until some condition is
satisfied. Specifying :deferred for a request doesn’t mean it
will be delayed, only that it can be. If the request
isn’t sent immediately, jsonrpc will make renewed efforts to
send it at certain key times during communication, such as when
receiving or sending other messages to the endpoint.
Before any attempt to send the request, the application-specific
conditions are checked. Since the jsonrpc library can’t know
what these conditions are, the program can use the
jsonrpc-connection-ready-p generic function (see 泛型函数) to specify them. The default method for this function
returns t, but you can add overriding methods that return
nil in some situations, based on the arguments passed to it,
which are the jsonrpc-connection object (see Overview) and whichever value you passed as the :deferred
keyword argument.
In database terminology, an atomic change is an indivisible change—it can succeed entirely or it can fail entirely, but it cannot partly succeed. A Lisp program can make a series of changes to one or several buffers as an atomic change group, meaning that either the entire series of changes will be installed in their buffers or, in case of an error, none of them will be.
To do this for one buffer, the one already current, simply write a
call to atomic-change-group around the code that makes the
changes, like this:
(atomic-change-group (insert foo) (delete-region x y))
If an error (or other nonlocal exit) occurs inside the body of
atomic-change-group, it unmakes all the changes in that buffer
that were during the execution of the body. This kind of change group
has no effect on any other buffers—any such changes remain.
If you need something more sophisticated, such as to make changes in
various buffers constitute one atomic group, you must directly call
lower-level functions that atomic-change-group uses.
This function sets up a change group for buffer buffer, which defaults to the current buffer. It returns a handle that represents the change group. You must use this handle to activate the change group and subsequently to finish it.
To use the change group, you must activate it. You must do this before making any changes in the text of buffer.
This function activates the change group that handle designates.
After you activate the change group, any changes you make in that buffer become part of it. Once you have made all the desired changes in the buffer, you must finish the change group. There are two ways to do this: you can either accept (and finalize) all the changes, or cancel them all.
This function accepts all the changes in the change group specified by handle, making them final.
This function cancels and undoes all the changes in the change group specified by handle.
You can cause some or all of the changes in a change group to be
considered as a single unit for the purposes of the undo
commands (see Undo) by using undo-amalgamate-change-group.
Amalgamate all the changes made in the change-group since the state
identified by handle. This function removes all undo boundaries
between undo records of changes since the state described by
handle. Usually, handle is the handle returned by
prepare-change-group, in which case all the changes since the
beginning of the change-group are amalgamated into a single undo unit.
Your code should use unwind-protect to make sure the group is
always finished. The call to activate-change-group should be
inside the unwind-protect, in case the user types C-g
just after it runs. (This is one reason why
prepare-change-group and activate-change-group are
separate functions, because normally you would call
prepare-change-group before the start of that
unwind-protect.) Once you finish the group, don’t use the
handle again—in particular, don’t try to finish the same group
twice.
To make a multibuffer change group, call prepare-change-group
once for each buffer you want to cover, then use nconc to
combine the returned values, like this:
(nconc (prepare-change-group buffer-1)
(prepare-change-group buffer-2))
You can then activate the multibuffer change group with a single call
to activate-change-group, and finish it with a single call to
accept-change-group or cancel-change-group.
Nested use of several change groups for the same buffer works as you would expect. Non-nested use of change groups for the same buffer will get Emacs confused, so don’t let it happen; the first change group you start for any given buffer should be the last one finished.
Emacs keeps track of change groups by assuming that by following
each cdr in buffer-undo-list, it will eventually arrive at the
cons it was set to at the time prepare-change-group was called.
If buffer-undo-list no longer contains that cons, Emacs will
lose track of any change groups, resulting in an error when the change
group is canceled. To avoid this, do not call any functions which
may edit the undo list in such a manner, when a change group is
active: notably, “amalgamating” commands such as delete-char,
which call undo-auto-amalgamate.
These hook variables let you arrange to take notice of changes in buffers (or in a particular buffer, if you make them buffer-local). See also Properties with Special Meanings, for how to detect changes to specific parts of the text.
The functions you use in these hooks should save and restore the match data if they do anything that uses regular expressions; otherwise, they will interfere in bizarre ways with the editing operations that call them. In addition, the functions in these hooks should avoid changing buffer text, faces, properties, overlays, and other aspects of the buffer-specific state except those that the hook functions themselves create and manage, because other parts of Emacs might become confused by such changes behind their back.
This variable holds a list of functions to call when Emacs is about to modify a buffer. Each function gets two arguments, the beginning and end of the region that is about to change, represented as integers. The buffer that is about to change is always the current buffer when the function is called.
This variable holds a list of functions to call after Emacs modifies a buffer. Each function receives three arguments: the beginning and end of the region just changed, and the length of the text that existed before the change. All three arguments are integers. The buffer that has been changed is always the current buffer when the function is called.
The length of the old text is the difference between the buffer positions before and after that text as it was before the change. As for the changed text, its length is simply the difference between the first two arguments.
Output of messages into the *Messages* buffer does not call these functions, and neither do certain internal buffer changes, such as changes in buffers created by Emacs internally for certain jobs, that should not be visible to Lisp programs.
The vast majority of buffer changing primitives will call
before-change-functions and after-change-functions in
balanced pairs, once for each change, where the arguments to these
hooks exactly delimit the change being made. Yet, hook functions
should not rely on this always being the case, because some complex
primitives call before-change-functions once before making
changes, and then call after-change-functions zero or more
times, depending on how many individual changes the primitive is
making. When that happens, the arguments to
before-change-functions will enclose a region in which the
individual changes are made, but won’t necessarily be the minimal such
region, and the arguments to each successive call of
after-change-functions will then delimit the part of text being
changed exactly. In general, we advise using either the before- or
the after-change hook, but not both.
The macro executes body normally, but arranges to call the after-change functions just once for a series of several changes—if that seems safe.
If a program makes several text changes in the same area of the buffer,
using the macro combine-after-change-calls around that part of
the program can make it run considerably faster when after-change hooks
are in use. When the after-change hooks are ultimately called, the
arguments specify a portion of the buffer including all of the changes
made within the combine-after-change-calls body.
Warning: You must not alter the values of
after-change-functions within
the body of a combine-after-change-calls form.
Warning: If the changes you combine occur in widely scattered parts of the buffer, this will still work, but it is not advisable, because it may lead to inefficient behavior for some change hook functions.
This executes body normally, except any buffer changes it makes
do not trigger the calls to before-change-functions and
after-change-functions. Instead there is a single call of each
of these hooks for the region enclosed by beg and end, the
parameters supplied to after-change-functions reflecting the
changes made to the size of the region by body.
The result of this macro is the result returned by body.
This macro is useful when a function makes a possibly large number of
repetitive changes to the buffer, and the change hooks would otherwise
take a long time to run, were they to be run for each individual
buffer modification. Emacs itself uses this macro, for example, in
the commands comment-region and uncomment-region.
Warning: You must not alter the values of
before-change-functions or after-change-function within
body.
Warning: You must not make any buffer changes outside of the region specified by beg and end.
This variable is a normal hook that is run whenever a buffer is changed that was previously in the unmodified state.
If this variable is non-nil, all of the change hooks are
disabled; none of them run. This affects all the hook variables
described above in this section, as well as the hooks attached to
certain special text properties (see Properties with Special Meanings) and overlay
properties (see Overlay Properties).
Also, this variable is bound to non-nil while running those
same hook variables, so that by default modifying the buffer from
a modification hook does not cause other modification hooks to be run.
If you do want modification hooks to be run in a particular piece of
code that is itself run from a modification hook, then rebind locally
inhibit-modification-hooks to nil. However, doing this
may cause recursive calls to the modification hooks, so be sure to
prepare for that (for example, by binding some variable which tells
your hook to do nothing).
We recommend that you only bind this variable for modifications that
do not result in lasting changes to buffer text contents (for example
face changes or temporary modifications). If you need to delay change
hooks during a series of changes (typically for performance reasons),
use combine-change-calls or combine-after-change-calls
instead.
Using before-change-functions and after-change-functions
can be difficult in practice because of a number of pitfalls, such as
the fact that the two calls are not always properly paired, or some
calls may be missing, either because some Emacs primitives failed to
properly pair them or because of incorrect use of
inhibit-modification-hooks. Furthermore,
many restrictions apply to those hook functions, such as the fact that
they basically should never modify the current buffer, nor use an
operation that may block, and they proceed quickly because
some commands may call these hooks a large number of times.
The Track-Changes library fundamentally provides an alternative API,
built on top of those hooks. Compared to after-change-functions,
the first important difference is that, instead of providing the bounds
of the change and the previous length, it provides the bounds of the
change and the actual previous content of that region. The need to
extract information from the original contents of the buffer is one of
the main reasons why some packages need to use both
before-change-functions and after-change-functions and
then try to match them up.
The second difference is that it decouples the notification of a change from the act of processing it, and it automatically combines into a single change operation all the changes that occur between the first change and the actual processing. This makes it natural and easy to process the changes at a larger granularity, such as once per command, and eliminates most of the restrictions that apply to the usual change hook functions, making it possible to use blocking operations or to modify the buffer.
To start tracking changes, you have to call
track-changes-register, passing it a signal function as
argument. This returns a tracker id which is used to identify
your change tracker to the other functions of the library.
When the buffer is modified, the library calls the signal
function to inform you of that change and immediately starts
accumulating subsequent changes into a single combined change.
The signal function serves only to warn that a modification
occurred but does not receive a description of the change. Also the
library will not call it again until after you retrieved the change.
To retrieve changes, you need to call track-changes-fetch, which
provides you with the bounds of the changes accumulated since the
last call, as well as the previous content of that region. It also
“re-arms” the signal function so that the library will call it
again after the next buffer modification.
This function creates a new change tracker. Change trackers are kept abstract, so we refer to them as mere identities, and the function thus returns the tracker’s id.
signal is a function that the library will call to notify of
a change. It will sometimes call it with a single argument and
sometimes with two. Upon the first change to the buffer since this
tracker last called track-changes-fetch, the library calls this
signal function with a single argument holding the id of
the tracker.
By default, the call to the signal function does not happen
immediately, but is instead postponed with a 0 seconds timer
(see Timers for Delayed Execution). This is usually desired to make sure the signal
function is not called too frequently and runs in a permissive context,
freeing the client from performance concerns or worries about which
operations might be problematic. If a client wants to have more
control, they can provide a non-nil value as the immediate
argument in which case the library calls the signal function
directly from after-change-functions. Beware that it means that
the signal function has to be careful not to modify the buffer or
use operations that may block.
If you’re not interested in the actual previous content of the buffer,
but are using this library only for its ability to combine many small
changes into a larger one and to delay the processing to a more
convenient time, you can specify a non-nil value for the
nobefore argument. In that case, track-change-fetch
provides you only with the length of the previous content, just like
after-change-functions. It also allows the library to save
some work.
While you may like to accumulate many small changes into larger ones,
you may not want to do that if the changes are too far apart. If you
specify a non-nil value for the disjoint argument, the library
will let you know when a change is about to occur “far” from the
currently pending ones by calling the signal function right away,
passing it two arguments this time: the id of the tracker, and the
number of characters that separates the upcoming change from the
already pending changes. This in itself does not prevent combining this
new change with the previous ones, so if you think the upcoming change
is indeed too far, you need to call track-change-fetch
right away.
Beware that when the signal function is called because of
a disjoint change, this happens directly from
before-change-functions, so the usual restrictions apply about
modifying the buffer or using operations that may block.
This is the function that lets you find out what has changed in the
buffer. By providing the tracker id you let the library figure
out which changes have already been seen by your tracker. Instead of
returning a description of the changes, track-changes-fetch calls
the func function with that description in the form of
3 arguments: beg, end, and before, where
beg..end delimit the region that was modified and
before describes the previous content of that region.
Usually before is a string containing the previous text of the
modified region, but if you specified a non-nil nobefore argument
to track-changes-register, then it is replaced by the number of
characters of that previous text.
In case no changes occurred since the last call,
track-changes-fetch simply does not call func and returns
nil. If changes did occur, it calls func and returns the value
returned by func. But note that func is called just once
regardless of how many changes occurred: those are summarized into
a single beg/end/before triplet.
In some cases, the library is not properly notified of all changes,
for example because of a bug in the low-level C code or because of an
improper use of inhibit-modification-hooks. When it detects such
a problem, func receives a beg..end region
which covers the whole buffer and the before argument is the
symbol error to indicate that the library was unable to determine
what was changed.
Once func finishes, track-changes-fetch re-enables the
signal function so that it will be called the next time a change
occurs. This is the reason why it calls func instead of returning
a description: it lets you process the change without worrying about the
risk that the signal function gets triggered in the middle of it,
because the signal is re-enabled only after func finishes.
This function tells the library that the tracker id does not need to know about buffer changes any more. Most clients will never want to stop tracking changes, but for clients such as minor modes, it is important to call this function when the minor mode is disabled, otherwise the tracker will keep accumulating changes and consume more and more resources.
This chapter covers the special issues relating to characters and how they are stored in strings and buffers.
Emacs buffers and strings support a large repertoire of characters from many different scripts, allowing users to type and display text in almost any known written language.
To support this multitude of characters and scripts, Emacs closely
follows the Unicode Standard. The Unicode Standard assigns a
unique number, called a codepoint, to each and every character.
The range of codepoints defined by Unicode, or the Unicode
codespace, is 0..#x10FFFF (in hexadecimal notation),
inclusive. Emacs extends this range with codepoints in the range
#x110000..#x3FFFFF, which it uses for representing characters
that are not unified with Unicode and raw 8-bit bytes that
cannot be interpreted as characters. Thus, a character codepoint in
Emacs is a 22-bit integer.
To conserve memory, Emacs does not hold fixed-length 22-bit numbers that are codepoints of text characters within buffers and strings. Rather, Emacs uses a variable-length internal representation of characters, that stores each character as a sequence of 1 to 5 8-bit bytes, depending on the magnitude of its codepoint25. For example, any ASCII character takes up only 1 byte, a Latin-1 character takes up 2 bytes, etc. We call this representation of text multibyte.
Outside Emacs, characters can be represented in many different encodings, such as ISO-8859-1, GB-2312, Big-5, etc. Emacs converts between these external encodings and its internal representation, as appropriate, when it reads text into a buffer or a string, or when it writes text to a disk file or passes it to some other process.
Occasionally, Emacs needs to hold and manipulate encoded text or binary non-text data in its buffers or strings. For example, when Emacs visits a file, it first reads the file’s text verbatim into a buffer, and only then converts it to the internal representation. Before the conversion, the buffer holds encoded text.
Encoded text is not really text, as far as Emacs is concerned, but
rather a sequence of raw 8-bit bytes. We call buffers and strings
that hold encoded text unibyte buffers and strings, because
Emacs treats them as a sequence of individual bytes. Usually, Emacs
displays unibyte buffers and strings as octal codes such as
\237. We recommend that you never use unibyte buffers and
strings except for manipulating encoded text or binary non-text data.
In a buffer, the buffer-local value of the variable
enable-multibyte-characters specifies the representation used.
The representation for a string is determined and recorded in the string
when the string is constructed.
This variable specifies the current buffer’s text representation.
If it is non-nil, the buffer contains multibyte text; otherwise,
it contains unibyte encoded text or binary non-text data.
You cannot set this variable directly; instead, use the function
set-buffer-multibyte to change a buffer’s representation.
Buffer positions are measured in character units. This function
returns the byte-position corresponding to buffer position
position in the current buffer. This is 1 at the start of the
buffer, and counts upward in bytes. If position is out of
range, the value is nil.
Return the buffer position, in character units, corresponding to given
byte-position in the current buffer. If byte-position is
out of range, the value is nil. In a multibyte buffer, an
arbitrary value of byte-position can be not at character
boundary, but inside a multibyte sequence representing a single
character; in this case, this function returns the buffer position of
the character whose multibyte sequence includes byte-position.
In other words, the value does not change for all byte positions that
belong to the same character.
The following two functions are useful when a Lisp program needs to map buffer positions to byte offsets in a file visited by the buffer.
This function is similar to position-bytes, but instead of byte
position in the current buffer it returns the offset from the
beginning of the current buffer’s file of the byte that corresponds to
the given character position in the buffer. The conversion
requires knowing how the text is encoded in the buffer’s file; this is
what the coding-system argument is for, defaulting to the value
of buffer-file-coding-system. The optional argument
quality specifies how accurate the result should be; it should
be one of the following:
exactThe result must be accurate. The function may need to encode and decode a large part of the buffer, which is expensive and can be slow.
approximateThe value can be an approximation. The function may avoid expensive processing and return an inexact result.
nilIf the exact result needs expensive processing, the function will
return nil rather than an approximation. This is the default
if the argument is omitted.
This function returns the buffer position corresponding to a file
position specified by byte, a zero-base byte offset from the
file’s beginning. The function performs the conversion opposite to
what bufferpos-to-filepos does. Optional arguments
quality and coding-system have the same meaning and values
as for bufferpos-to-filepos.
Return t if string is a multibyte string, nil
otherwise. This function also returns nil if string is
some object other than a string.
This function returns the number of bytes in string.
If string is a multibyte string, this can be greater than
(length string).
This function concatenates all its argument bytes and makes the result a unibyte string.
By default, Emacs starts in multibyte mode: it stores the contents of buffers and strings using an internal encoding that represents non-ASCII characters using multi-byte sequences. Multibyte mode allows you to use all the supported languages and scripts without limitations.
Under very special circumstances, you may want to disable multibyte character support, for a specific buffer. When multibyte characters are disabled in a buffer, we call that unibyte mode. In unibyte mode, each character in the buffer has a character code ranging from 0 through 255 (0377 octal); 0 through 127 (0177 octal) represent ASCII characters, and 128 (0200 octal) through 255 (0377 octal) represent non-ASCII characters.
To edit a particular file in unibyte representation, visit it using
find-file-literally. See 访问文件的函数. You can
convert a multibyte buffer to unibyte by saving it to a file, killing
the buffer, and visiting the file again with
find-file-literally. Alternatively, you can use C-x
RET c (universal-coding-system-argument) and specify
‘raw-text’ as the coding system with which to visit or save a
file. See Specifying a Coding System for File Text in GNU Emacs Manual. Unlike find-file-literally, finding
a file as ‘raw-text’ doesn’t disable format conversion,
uncompression, or auto mode selection.
The buffer-local variable enable-multibyte-characters is
non-nil in multibyte buffers, and nil in unibyte ones.
The mode line also indicates whether a buffer is multibyte or not.
With a graphical display, in a multibyte buffer, the portion of the
mode line that indicates the character set has a tooltip that (amongst
other things) says that the buffer is multibyte. In a unibyte buffer,
the character set indicator is absent. Thus, in a unibyte buffer
(when using a graphical display) there is normally nothing before the
indication of the visited file’s end-of-line convention (colon,
backslash, etc.), unless you are using an input method.
You can turn off multibyte support in a specific buffer by invoking the
command toggle-enable-multibyte-characters in that buffer.
Emacs can convert unibyte text to multibyte; it can also convert multibyte text to unibyte, provided that the multibyte text contains only ASCII and 8-bit raw bytes. In general, these conversions happen when inserting text into a buffer, or when putting text from several strings together in one string. You can also explicitly convert a string’s contents to either representation.
Emacs chooses the representation for a string based on the text from which it is constructed. The general rule is to convert unibyte text to multibyte text when combining it with other multibyte text, because the multibyte representation is more general and can hold whatever characters the unibyte text has.
When inserting text into a buffer, Emacs converts the text to the
buffer’s representation, as specified by
enable-multibyte-characters in that buffer. In particular, when
you insert multibyte text into a unibyte buffer, Emacs converts the text
to unibyte, even though this conversion cannot in general preserve all
the characters that might be in the multibyte text. The other natural
alternative, to convert the buffer contents to multibyte, is not
acceptable because the buffer’s representation is a choice made by the
user that cannot be overridden automatically.
Converting unibyte text to multibyte text leaves ASCII characters unchanged, and converts bytes with codes 128 through 255 to the multibyte representation of raw eight-bit bytes.
Converting multibyte text to unibyte converts all ASCII and eight-bit characters to their single-byte form, but loses information for non-ASCII characters by discarding all but the low 8 bits of each character’s codepoint. Converting unibyte text to multibyte and back to unibyte reproduces the original unibyte text.
The next two functions either return the argument string, or a newly created string with no text properties.
This function returns a multibyte string containing the same sequence
of characters as string. If string is a multibyte string,
it is returned unchanged. The function assumes that string
includes only ASCII characters and raw 8-bit bytes; the
latter are converted to their multibyte representation corresponding
to the codepoints #x3FFF80 through #x3FFFFF, inclusive
(see codepoints).
This function returns a unibyte string containing the same sequence of
characters as string. If string is a unibyte string, it
is returned unchanged. Otherwise, ASCII characters and
characters in the eight-bit charset are converted to their
corresponding byte values. Use this function for string
arguments that contain only ASCII and eight-bit characters;
the function signals an error if any other characters are encountered.
This function returns a unibyte string containing a single byte of character data, byte. It signals an error if byte is not an integer between 0 and 255.
This converts the multibyte character char to a unibyte character, and returns that character. If char is neither ASCII nor eight-bit, the function returns −1.
This converts the unibyte character char to a multibyte character, assuming char is either ASCII or raw 8-bit byte.
Sometimes it is useful to examine an existing buffer or string as multibyte when it was unibyte, or vice versa.
Set the representation type of the current buffer. If multibyte
is non-nil, the buffer becomes multibyte. If multibyte
is nil, the buffer becomes unibyte.
This function leaves the buffer contents unchanged when viewed as a sequence of bytes. As a consequence, it can change the contents viewed as characters; for instance, a sequence of three bytes which is treated as one character in multibyte representation will count as three characters in unibyte representation. Eight-bit characters representing raw bytes are an exception. They are represented by one byte in a unibyte buffer, but when the buffer is set to multibyte, they are converted to two-byte sequences, and vice versa.
This function sets enable-multibyte-characters to record which
representation is in use. It also adjusts various data in the buffer
(including overlays, text properties and markers) so that they cover the
same text as they did before.
This function signals an error if the buffer is narrowed, since the narrowing might have occurred in the middle of multibyte character sequences.
This function also signals an error if the buffer is an indirect buffer. An indirect buffer always inherits the representation of its base buffer.
The following two functions are obsolete and will be removed in a future
version of Emacs; use encode-coding-string instead.
If string is already a unibyte string, this function returns string itself. Otherwise, it returns a new string with the same bytes as string, but treating each byte as a separate character (so that the value may have more characters than string); as an exception, each eight-bit character representing a raw byte is converted into a single byte. The newly-created string contains no text properties.
If string is a multibyte string, this function returns string itself. Otherwise, it returns a new string with the same bytes as string, but treating each multibyte sequence as one character. This means that the value may have fewer characters than string has. If a byte sequence in string is invalid as a multibyte representation of a single character, each byte in the sequence is treated as a raw 8-bit byte. The newly-created string contains no text properties.
The unibyte and multibyte text representations use different
character codes. The valid character codes for unibyte representation
range from 0 to #xFF (255)—the values that can fit in one
byte. The valid character codes for multibyte representation range
from 0 to #x3FFFFF. In this code space, values 0 through
#x7F (127) are for ASCII characters, and values
#x80 (128) through #x3FFF7F (4194175) are for
non-ASCII characters.
Emacs character codes are a superset of the Unicode standard.
Values 0 through #x10FFFF (1114111) correspond to Unicode
characters of the same codepoint; values #x110000 (1114112)
through #x3FFF7F (4194175) represent characters that are not
unified with Unicode; and values #x3FFF80 (4194176) through
#x3FFFFF (4194303) represent eight-bit raw bytes.
This returns t if charcode is a valid character, and
nil otherwise.
(characterp 65)
⇒ t
(characterp 4194303)
⇒ t
(characterp 4194304)
⇒ nil
This function returns the largest value that a valid character
codepoint can have in Emacs. If the optional argument unicode
is non-nil, it returns the largest character codepoint defined
by the Unicode Standard (which is smaller than the maximum codepoint
supported by Emacs).
(characterp (max-char))
⇒ t
(characterp (1+ (max-char)))
⇒ nil
This function returns the character whose Unicode name is string.
If ignore-case is non-nil, case is ignored in string.
This function returns nil if string does not name a character.
;; U+03A3
(= (char-from-name "GREEK CAPITAL LETTER SIGMA") #x03A3)
⇒ t
This function returns the Unicode name of char. It returns
nil if char is not a character or has no Unicode name.
This function returns the byte at character position pos in the current buffer. If the current buffer is unibyte, this is literally the byte at that position. If the buffer is multibyte, byte values of ASCII characters are the same as character codepoints, whereas eight-bit raw bytes are converted to their 8-bit codes. The function signals an error if the character at pos is non-ASCII.
The optional argument string means to get a byte value from that string instead of the current buffer.
A character property is a named attribute of a character that specifies how the character behaves and how it should be handled during text processing and display. Thus, character properties are an important part of specifying the character’s semantics.
On the whole, Emacs follows the Unicode Standard in its implementation of character properties. In particular, Emacs supports the Unicode Character Property Model, and the Emacs character property database is derived from the Unicode Character Database (UCD). See the Character Properties chapter of the Unicode Standard, for a detailed description of Unicode character properties and their meaning. This section assumes you are already familiar with that chapter of the Unicode Standard, and want to apply that knowledge to Emacs Lisp programs.
In Emacs, each property has a name, which is a symbol, and a set of
possible values, whose types depend on the property; if a character
does not have a certain property, the value is nil. As a
general rule, the names of character properties in Emacs are produced
from the corresponding Unicode properties by downcasing them and
replacing each ‘_’ character with a dash ‘-’. For example,
Canonical_Combining_Class becomes
canonical-combining-class. However, sometimes we shorten the
names to make their use easier.
Some codepoints are left unassigned by the UCD—they don’t correspond to any character. The Unicode Standard defines default values of properties for such codepoints; they are mentioned below for each property.
Here is the full list of value types for all the character properties that Emacs knows about:
nameCorresponds to the Name Unicode property. The value is a
string consisting of upper-case Latin letters A to Z, digits, spaces,
and hyphen ‘-’ characters. For unassigned codepoints, the value
is nil.
general-category ¶Corresponds to the General_Category Unicode property. The
value is a symbol whose name is a 2-letter abbreviation of the
character’s classification. For unassigned codepoints, the value
is Cn.
canonical-combining-classCorresponds to the Canonical_Combining_Class Unicode property.
The value is an integer. For unassigned codepoints, the value
is zero.
bidi-class ¶Corresponds to the Unicode Bidi_Class property. The value is a
symbol whose name is the Unicode directional type of the
character. Emacs uses this property when it reorders bidirectional
text for display (see Bidirectional Display). For unassigned
codepoints, the value depends on the code blocks to which the
codepoint belongs: most unassigned codepoints get the value of
L (strong L), but some get values of AL (Arabic letter)
or R (strong R).
decompositionCorresponds to the Unicode properties Decomposition_Type and
Decomposition_Value. The value is a list, whose first element
may be a symbol representing a compatibility formatting tag, such as
small26; the other elements are characters that give the
compatibility decomposition sequence of this character. For
characters that don’t have decomposition sequences, and for unassigned
codepoints, the value is a list with a single member, the character
itself.
decimal-digit-valueCorresponds to the Unicode Numeric_Value property for
characters whose Numeric_Type is ‘Decimal’. The value is
an integer, or nil if the character has no decimal digit value.
For unassigned codepoints, the value is nil, which means
NaN, or “not a number”.
digit-valueCorresponds to the Unicode Numeric_Value property for
characters whose Numeric_Type is ‘Digit’. The value is an
integer. Examples of such characters include compatibility subscript
and superscript digits, for which the value is the corresponding
number. For characters that don’t have any numeric value, and for
unassigned codepoints, the value is nil, which means
NaN.
numeric-valueCorresponds to the Unicode Numeric_Value property for
characters whose Numeric_Type is ‘Numeric’. The value of
this property is a number. Examples of characters that have this
property include fractions, subscripts, superscripts, Roman numerals,
currency numerators, and encircled numbers. For example, the value of
this property for the character U+2155 VULGAR FRACTION ONE
FIFTH is 0.2. For characters that don’t have any numeric
value, and for unassigned codepoints, the value is nil, which
means NaN.
mirrored ¶Corresponds to the Unicode Bidi_Mirrored property. The value
of this property is a symbol, either Y or N. For
unassigned codepoints, the value is N.
mirroringCorresponds to the Unicode Bidi_Mirroring_Glyph property. The
value of this property is a character whose glyph represents the
mirror image of the character’s glyph, or nil if there’s no
defined mirroring glyph. All the characters whose mirrored
property is N have nil as their mirroring
property; however, some characters whose mirrored property is
Y also have nil for mirroring, because no
appropriate characters exist with mirrored glyphs. Emacs uses this
property to display mirror images of characters when appropriate
(see Bidirectional Display). For unassigned codepoints, the value
is nil.
paired-bracketCorresponds to the Unicode Bidi_Paired_Bracket property. The
value of this property is the codepoint of a character’s paired
bracket, or nil if the character is not a bracket character.
This establishes a mapping between characters that are treated as
bracket pairs by the Unicode Bidirectional Algorithm; Emacs uses this
property when it decides how to reorder for display parentheses,
braces, and other similar characters (see Bidirectional Display).
bracket-typeCorresponds to the Unicode Bidi_Paired_Bracket_Type property.
For characters whose paired-bracket property is non-nil,
the value of this property is a symbol, either o (for opening
bracket characters) or c (for closing bracket characters). For
characters whose paired-bracket property is nil, the
value is the symbol n (None). Like paired-bracket, this
property is used for bidirectional display.
old-nameCorresponds to the Unicode Unicode_1_Name property. The value
is a string. For unassigned codepoints, and characters that have no
value for this property, the value is nil.
iso-10646-commentCorresponds to the Unicode ISO_Comment property. The value is
either a string or nil. For unassigned codepoints, the value
is nil.
uppercaseCorresponds to the Unicode Simple_Uppercase_Mapping property.
The value of this property is a single character. For unassigned
codepoints, the value is nil, which means the character itself.
lowercaseCorresponds to the Unicode Simple_Lowercase_Mapping property.
The value of this property is a single character. For unassigned
codepoints, the value is nil, which means the character itself.
titlecaseCorresponds to the Unicode Simple_Titlecase_Mapping property.
Title case is a special form of a character used when the first
character of a word needs to be capitalized. The value of this
property is a single character. For unassigned codepoints, the value
is nil, which means the character itself.
special-uppercaseCorresponds to Unicode language- and context-independent special upper-casing
rules. The value of this property is a string (which may be empty). For
example for U+00DF LATIN SMALL LETTER SHARP S the value is
"SS". This mapping overrides the uppercase property, and
thus the current case table. For characters with no special mapping,
the value is nil, which means the uppercase property needs to
be consulted instead.
special-lowercaseCorresponds to Unicode language- and context-independent special
lower-casing rules. The value of this property is a string (which may
be empty). For example for U+0130 LATIN CAPITAL LETTER I
WITH DOT ABOVE the value is "i\u0307" (i.e., a 2-character string
consisting of LATIN SMALL LETTER I followed by U+0307
COMBINING DOT ABOVE). This mapping overrides the lowercase
property, and thus the current case table. For characters with no
special mapping, the value is nil, which means the lowercase
property needs to be consulted instead.
special-titlecaseCorresponds to Unicode unconditional special title-casing rules. The value of
this property is a string (which may be empty). For example for
U+FB01 LATIN SMALL LIGATURE FI the value is "Fi". This
mapping overrides the titlecase property, and thus the current
case table. For characters with no special mapping, the value is
nil, which means the titlecase property needs to be consulted
instead.
This function returns the value of char’s propname property.
(get-char-code-property ?\s 'general-category)
⇒ Zs
(get-char-code-property ?1 'general-category)
⇒ Nd
;; U+2084
(get-char-code-property ?\N{SUBSCRIPT FOUR}
'digit-value)
⇒ 4
;; U+2155
(get-char-code-property ?\N{VULGAR FRACTION ONE FIFTH}
'numeric-value)
⇒ 0.2
;; U+2163
(get-char-code-property ?\N{ROMAN NUMERAL FOUR}
'numeric-value)
⇒ 4
(get-char-code-property ?\( 'paired-bracket)
⇒ 41 ; closing parenthesis
(get-char-code-property ?\) 'bracket-type)
⇒ c
This function returns the description string of property prop’s
value, or nil if value has no description.
(char-code-property-description 'general-category 'Zs)
⇒ "Separator, Space"
(char-code-property-description 'general-category 'Nd)
⇒ "Number, Decimal Digit"
(char-code-property-description 'numeric-value '1/5)
⇒ nil
This function stores value as the value of the property propname for the character char.
The value of this variable is a char-table (see 字符表) that
specifies, for each character, its Unicode General_Category
property as a symbol.
The value of this variable is a char-table that specifies, for each character, a symbol whose name is the script to which the character belongs, according to the Unicode Standard classification of the Unicode code space into script-specific blocks. This char-table has a single extra slot whose value is the list of all script symbols. Note that Emacs’s classification of characters into scripts is not a 1-for-1 reflection of the Unicode standard, for example there is no ‘symbol’ script in Unicode.
The value of this variable is a char-table that specifies the width of each character in columns that it will occupy on the screen.
The value of this variable is a char-table that specifies, for each
character, whether it is printable or not. That is, if evaluating
(aref printable-chars char) results in t, the character
is printable, and if it results in nil, it is not.
An Emacs character set, or charset, is a set of characters
in which each character is assigned a numeric code point. (The
Unicode Standard calls this a coded character set.) Each Emacs
charset has a name which is a symbol. A single character can belong
to any number of different character sets, but it will generally have
a different code point in each charset. Examples of character sets
include ascii, iso-8859-1, greek-iso8859-7, and
windows-1255. The code point assigned to a character in a
charset is usually different from its code point used in Emacs buffers
and strings.
Emacs defines several special character sets. The character set
unicode includes all the characters whose Emacs code points are
in the range 0..#x10FFFF. The character set emacs
includes all ASCII and non-ASCII characters.
Finally, the eight-bit charset includes the 8-bit raw bytes;
Emacs uses it to represent raw bytes encountered in text.
Returns t if object is a symbol that names a character set,
nil otherwise.
The value is a list of all defined character set names.
This function returns a list of all defined character sets ordered by
their priority. If highestp is non-nil, the function
returns a single character set of the highest priority.
This function makes charsets the highest priority character sets.
This function returns the name of the character set of highest
priority that character belongs to. ASCII characters
are an exception: for them, this function always returns ascii.
If restriction is non-nil, it should be a list of
charsets to search. Alternatively, it can be a coding system, in
which case the returned charset must be supported by that coding
system (see Coding Systems).
This function returns the property list of the character set charset. Although charset is a symbol, this is not the same as the property list of that symbol. Charset properties include important information about the charset, such as its documentation string, short name, etc.
This function sets the propname property of charset to the given value.
This function returns the value of charsets property propname.
This command displays a list of characters in the character set charset.
Emacs can convert between its internal representation of a character and the character’s codepoint in a specific charset. The following two functions support these conversions.
This function decodes a character that is assigned a code-point
in charset, to the corresponding Emacs character, and returns
it. If charset doesn’t contain a character of that code point,
the value is nil.
For backward compatibility, if code-point doesn’t fit in a Lisp
fixnum (see most-positive-fixnum), it can be
specified as a cons cell (high . low), where
low are the lower 16 bits of the value and high are the
high 16 bits. This usage is obsolescent.
This function returns the code point assigned to the character
char in charset. If
charset doesn’t have a codepoint for char, the value is
nil.
The following function comes in handy for applying a certain function to all or part of the characters in a charset:
Call function for characters in charset. function
is called with two arguments. The first one is a cons cell
(from . to), where from and to
indicate a range of characters contained in charset. The second
argument passed to function is arg, or nil if
arg is omitted.
By default, the range of codepoints passed to function includes
all the characters in charset, but optional arguments
from-code and to-code limit that to the range of
characters between these two codepoints of charset. If either
of them is nil, it defaults to the first or last codepoint of
charset, respectively. Note that from-code and
to-code are charset’s codepoints, not the Emacs codes of
characters; by contrast, the values from and to in the
cons cell passed to function are Emacs character codes.
Those Emacs character codes are either Unicode code points, or Emacs
internal code points that extend Unicode and are beyond the Unicode
range of characters 0..#x10FFFF (see Text Representations).
The latter happens rarely, with legacy CJK charsets for codepoints of
charset which specify characters not yet unified with Unicode.
Sometimes it is useful to find out which character set a particular character belongs to. One use for this is in determining which coding systems (see Coding Systems) are capable of representing all of the text in question; another is to determine the font(s) for displaying that text.
This function returns the charset of highest priority containing the
character at position pos in the current buffer. If pos
is omitted or nil, it defaults to the current value of point.
If pos is out of range, the value is nil.
This function returns a list of the character sets of highest priority that contain characters in the current buffer between positions beg and end.
The optional argument translation specifies a translation table
to use for scanning the text (see Translation of Characters). If
it is non-nil, then each character in the region is translated
through this table, and the value returned describes the translated
characters instead of the characters actually in the buffer.
This function returns a list of character sets of highest priority
that contain characters in string. It is just like
find-charset-region, except that it applies to the contents of
string instead of part of the current buffer.
A translation table is a char-table (see 字符表) that specifies a mapping of characters into characters. These tables are used in encoding and decoding, and for other purposes. Some coding systems specify their own particular translation tables; there are also default translation tables which apply to all other coding systems.
A translation table has two extra slots. The first is either
nil or a translation table that performs the reverse
translation; the second is the maximum number of characters to look up
for translating sequences of characters (see the description of
make-translation-table-from-alist below).
This function returns a translation table based on the argument
translations. Each element of translations should be a
list of elements of the form (from . to); this says
to translate the character from into to.
The arguments and the forms in each argument are processed in order, and if a previous form already translates to to some other character, say to-alt, from is also translated to to-alt.
During decoding, the translation table’s translations are applied to
the characters that result from ordinary decoding. If a coding system
has the property :decode-translation-table, that specifies the
translation table to use, or a list of translation tables to apply in
sequence. (This is a property of the coding system, as returned by
coding-system-get, not a property of the symbol that is the
coding system’s name. See Basic Concepts of
Coding Systems.) Finally, if
standard-translation-table-for-decode is non-nil, the
resulting characters are translated by that table.
During encoding, the translation table’s translations are applied to
the characters in the buffer, and the result of translation is
actually encoded. If a coding system has property
:encode-translation-table, that specifies the translation table
to use, or a list of translation tables to apply in sequence. In
addition, if the variable standard-translation-table-for-encode
is non-nil, it specifies the translation table to use for
translating the result.
This is the default translation table for decoding. If a coding
system specifies its own translation tables, the table that is the
value of this variable, if non-nil, is applied after them.
This is the default translation table for encoding. If a coding
system specifies its own translation tables, the table that is the
value of this variable, if non-nil, is applied after them.
Self-inserting characters are translated through this translation table before they are inserted. Search commands also translate their input through this table, so they can compare more reliably with what’s in the buffer.
This variable automatically becomes buffer-local when set.
This function returns a translation table made from vec that is
an array of 256 elements to map bytes (values 0 through #xFF) to
characters. Elements may be nil for untranslated bytes. The
returned table has a translation table for reverse mapping in the
first extra slot, and the value 1 in the second extra slot.
This function provides an easy way to make a private coding system
that maps each byte to a specific character. You can specify the
returned table and the reverse translation table using the properties
:decode-translation-table and :encode-translation-table
respectively in the props argument to
define-coding-system.
This function is similar to make-translation-table but returns
a complex translation table rather than a simple one-to-one mapping.
Each element of alist is of the form (from
. to), where from and to are either characters or
vectors specifying a sequence of characters. If from is a
character, that character is translated to to (i.e., to a
character or a character sequence). If from is a vector of
characters, that sequence is translated to to. The returned
table has a translation table for reverse mapping in the first extra
slot, and the maximum length of all the from character sequences
in the second extra slot.
When Emacs reads or writes a file, and when Emacs sends text to a subprocess or receives text from a subprocess, it normally performs character code conversion and end-of-line conversion as specified by a particular coding system.
How to define a coding system is an arcane matter, and is not documented here.
Character code conversion involves conversion between the internal representation of characters used inside Emacs and some other encoding. Emacs supports many different encodings, in that it can convert to and from them. For example, it can convert text to or from encodings such as Latin 1, Latin 2, Latin 3, Latin 4, Latin 5, and several variants of ISO 2022. In some cases, Emacs supports several alternative encodings for the same characters; for example, there are three coding systems for the Cyrillic (Russian) alphabet: ISO, Alternativnyj, and KOI8.
Every coding system specifies a particular set of character code
conversions, but the coding system undecided is special: it
leaves the choice unspecified, to be chosen heuristically for each
file or string, based on the file’s or string’s data, when they are
decoded or encoded. The coding system prefer-utf-8 is like
undecided, but it prefers to choose utf-8 when possible.
In general, a coding system doesn’t guarantee roundtrip identity: decoding a byte sequence using a coding system, then encoding the resulting text in the same coding system, can produce a different byte sequence. But some coding systems do guarantee that the byte sequence will be the same as what you originally decoded. Here are a few examples:
iso-8859-1, utf-8, big5, shift_jis, euc-jp
Encoding buffer text and then decoding the result can also fail to reproduce the original text. For instance, if you encode a character with a coding system which does not support that character, the result is unpredictable, and thus decoding it using the same coding system may produce a different text. Currently, Emacs can’t report errors that result from encoding unsupported characters.
End of line conversion handles three different conventions used on various systems for representing end of line in files. The Unix convention, used on GNU and Unix systems, and macOS, is to use the linefeed character (also called newline). The DOS convention, used on MS-Windows and MS-DOS systems, is to use a carriage return and a linefeed. The Mac convention, used in Classic Mac OS and now rare outside of legacy software, is to use just carriage return.
Base coding systems such as latin-1 leave the end-of-line
conversion unspecified, to be chosen based on the data. Variant
coding systems such as latin-1-unix, latin-1-dos and
latin-1-mac specify the end-of-line conversion explicitly as
well. Most base coding systems have three corresponding variants whose
names are formed by adding ‘-unix’, ‘-dos’ and ‘-mac’.
The coding system raw-text is special in that it prevents
character code conversion, and causes the buffer visited with this
coding system to be a unibyte buffer. For historical reasons, you can
save both unibyte and multibyte text with this coding system. When
you use raw-text to encode multibyte text, it does perform one
character code conversion: it converts eight-bit characters to their
single-byte external representation. raw-text does not specify
the end-of-line conversion, allowing that to be determined as usual by
the data, and has the usual three variants which specify the
end-of-line conversion.
no-conversion (and its alias binary) is equivalent to
raw-text-unix: it specifies no conversion of either character
codes or end-of-line.
The coding system utf-8-emacs specifies that the data is
represented in the internal Emacs encoding (see Text Representations). This is like raw-text in that no code
conversion happens, but different in that the result is multibyte
data. The name emacs-internal is an alias for
utf-8-emacs-unix (so it forces no conversion of end-of-line,
unlike utf-8-emacs, which can decode all 3 kinds of
end-of-line conventions). Since this coding system can represent all
the characters supported by Emacs in its buffers and strings, we
recommend using it whenever saving text for internal purposes, such as
caching.
This function returns the specified property of the coding system
coding-system. Most coding system properties exist for internal
purposes, but one that you might find useful is :mime-charset.
That property’s value is the name used in MIME for the character coding
which this coding system can read and write. Examples:
(coding-system-get 'iso-latin-1 :mime-charset)
⇒ iso-8859-1
(coding-system-get 'iso-2022-cn :mime-charset)
⇒ iso-2022-cn
(coding-system-get 'cyrillic-koi8 :mime-charset)
⇒ koi8-r
The value of the :mime-charset property is also defined
as an alias for the coding system.
This function returns the list of aliases of coding-system.
The principal purpose of coding systems is for use in reading and
writing files. The function insert-file-contents uses a coding
system to decode the file data, and write-region uses one to
encode the buffer contents.
You can specify the coding system to use either explicitly
(see Specifying a Coding System for One Operation), or implicitly using a default
mechanism (see Default Coding Systems). But these methods may not
completely specify what to do. For example, they may choose a coding
system such as undecided which leaves the character code
conversion to be determined from the data. In these cases, the I/O
operation finishes the job of choosing a coding system. Very often
you will want to find out afterwards which coding system was chosen.
This buffer-local variable records the coding system used for saving the
buffer and for writing part of the buffer with write-region. If
the text to be written cannot be safely encoded using the coding system
specified by this variable, these operations select an alternative
encoding by calling the function select-safe-coding-system
(see User-Chosen Coding Systems). If selecting a different encoding
requires asking the user to specify a coding system,
buffer-file-coding-system is updated to the newly selected coding
system.
buffer-file-coding-system does not affect sending text
to a subprocess.
This variable specifies the coding system for saving the buffer (by
overriding buffer-file-coding-system). Note that it is not used
for write-region.
When a command to save the buffer starts out to use
buffer-file-coding-system (or save-buffer-coding-system),
and that coding system cannot handle
the actual text in the buffer, the command asks the user to choose
another coding system (by calling select-safe-coding-system).
After that happens, the command also updates
buffer-file-coding-system to represent the coding system that
the user specified.
I/O operations for files and subprocesses set this variable to the coding system name that was used. The explicit encoding and decoding functions (see Explicit Encoding and Decoding) set it too.
Warning: Since receiving subprocess output sets this variable, it can change whenever Emacs waits; therefore, you should copy the value shortly after the function call that stores the value you are interested in.
The variable selection-coding-system specifies how to encode
selections for the window system. See Window System Selections.
The variable file-name-coding-system specifies the coding
system to use for encoding file names. Emacs encodes file names using
that coding system for all file operations. If
file-name-coding-system is nil, Emacs uses a default
coding system determined by the selected language environment. In the
default language environment, any non-ASCII characters in
file names are not encoded specially; they appear in the file system
using the internal Emacs representation.
Warning: if you change file-name-coding-system (or
the language environment) in the middle of an Emacs session, problems
can result if you have already visited files whose names were encoded
using the earlier coding system and are handled differently under the
new coding system. If you try to save one of these buffers under the
visited file name, saving may use the wrong file name, or it may get
an error. If such a problem happens, use C-x C-w to specify a
new file name for that buffer.
On Windows 2000 and later, Emacs by default uses Unicode APIs to
pass file names to the OS, so the value of
file-name-coding-system is largely ignored. Lisp applications
that need to encode or decode file names on the Lisp level should use
utf-8 coding-system when system-type is
windows-nt; the conversion of UTF-8 encoded file names to the
encoding appropriate for communicating with the OS is performed
internally by Emacs.
Here are the Lisp facilities for working with coding systems:
This function returns a list of all coding system names (symbols). If
base-only is non-nil, the value includes only the
base coding systems. Otherwise, it includes alias and variant coding
systems as well.
This function returns t if object is a coding system
name or nil.
This function checks the validity of coding-system. If that is
valid, it returns coding-system. If coding-system is
nil, the function returns nil. For any other values, it
signals an error whose error-symbol is coding-system-error
(see signal).
This function returns the type of end-of-line (a.k.a. eol)
conversion used by coding-system. If coding-system
specifies a certain eol conversion, the return value is an integer 0,
1, or 2, standing for unix, dos, and mac,
respectively. If coding-system doesn’t specify eol conversion
explicitly, the return value is a vector of coding systems, each one
with one of the possible eol conversion types, like this:
(coding-system-eol-type 'latin-1)
⇒ [latin-1-unix latin-1-dos latin-1-mac]
If this function returns a vector, Emacs will decide, as part of the
text encoding or decoding process, what eol conversion to use. For
decoding, the end-of-line format of the text is auto-detected, and the
eol conversion is set to match it (e.g., DOS-style CRLF format will
imply dos eol conversion). For encoding, the eol conversion is
taken from the appropriate default coding system (e.g.,
default value of buffer-file-coding-system for
buffer-file-coding-system), or from the default eol conversion
appropriate for the underlying platform.
This function returns a coding system which is like coding-system
except for its eol conversion, which is specified by eol-type.
eol-type should be unix, dos, mac, or
nil. If it is nil, the returned coding system determines
the end-of-line conversion from the data.
eol-type may also be 0, 1 or 2, standing for unix,
dos and mac, respectively.
This function returns a coding system which uses the end-of-line
conversion of eol-coding, and the text conversion of
text-coding. If text-coding is nil, it returns
undecided, or one of its variants according to eol-coding.
This function returns a list of coding systems that could be used to encode a text between from and to. All coding systems in the list can safely encode any multibyte characters in that portion of the text.
If the text contains no multibyte characters, the function returns the
list (undecided).
This function returns a list of coding systems that could be used to
encode the text of string. All coding systems in the list can
safely encode any multibyte characters in string. If the text
contains no multibyte characters, this returns the list
(undecided).
This function returns a list of coding systems that could be used to encode all the character sets in the list charsets.
This function checks whether coding systems in the list
coding-system-list can encode all the characters in the region
between start and end. If all of the coding systems in
the list can encode the specified text, the function returns
nil. If some coding systems cannot encode some of the
characters, the value is an alist, each element of which has the form
(coding-system1 pos1 pos2 …), meaning
that coding-system1 cannot encode characters at buffer positions
pos1, pos2, ....
start may be a string, in which case end is ignored and the returned value references string indices instead of buffer positions.
This function chooses a plausible coding system for decoding the text from start to end. This text should be a byte sequence, i.e., unibyte text or multibyte text with only ASCII and eight-bit characters (see Explicit Encoding and Decoding).
Normally this function returns a list of coding systems that could
handle decoding the text that was scanned. They are listed in order of
decreasing priority. But if highest is non-nil, then the
return value is just one coding system, the one that is highest in
priority.
If the region contains only ASCII characters except for such
ISO-2022 control characters ISO-2022 as ESC, the value is
undecided or (undecided), or a variant specifying
end-of-line conversion, if that can be deduced from the text.
If the region contains null bytes, the value is no-conversion,
even if the region contains text encoded in some coding system.
This function is like detect-coding-region except that it
operates on the contents of string instead of bytes in the buffer.
If this variable has a non-nil value, null bytes are ignored
when detecting the encoding of a region or a string. This allows the
encoding of text that contains null bytes to be correctly detected,
such as Info files with Index nodes.
If this variable has a non-nil value, ISO-2022 escape sequences
are ignored when detecting the encoding of a region or a string. The
result is that no text is ever detected as encoded in some ISO-2022
encoding, and all escape sequences become visible in a buffer.
Warning: Use this variable with extreme caution,
because many files in the Emacs distribution use ISO-2022 encoding.
This function returns the list of character sets (see Character Sets) supported by coding-system. Some coding systems that support too many character sets to list them all yield special values:
(emacs).
(unicode).
iso-2022.
emacs-mule.
See Process Information, in
particular the description of the functions
process-coding-system and set-process-coding-system, for
how to examine or set the coding systems used for I/O to a subprocess.
This function selects a coding system for encoding specified text, asking the user to choose if necessary. Normally the specified text is the text in the current buffer between from and to. If from is a string, the string specifies the text to encode, and to is ignored.
If the specified text includes raw bytes (see Text Representations), select-safe-coding-system suggests
raw-text for its encoding.
If default-coding-system is non-nil, that is the first
coding system to try; if that can handle the text,
select-safe-coding-system returns that coding system. It can
also be a list of coding systems; then the function tries each of them
one by one. After trying all of them, it next tries the current
buffer’s value of buffer-file-coding-system (if it is not
undecided), then the default value of
buffer-file-coding-system and finally the user’s most
preferred coding system, which the user can set using the command
prefer-coding-system (see Recognizing
Coding Systems in The GNU Emacs Manual).
If one of those coding systems can safely encode all the specified
text, select-safe-coding-system chooses it and returns it.
Otherwise, it asks the user to choose from a list of coding systems
which can encode all the text, and returns the user’s choice.
default-coding-system can also be a list whose first element is
t and whose other elements are coding systems. Then, if no coding
system in the list can handle the text, select-safe-coding-system
queries the user immediately, without trying any of the three
alternatives described above. This is handy for checking only the
coding systems in the list.
The optional argument accept-default-p determines whether a
coding system selected without user interaction is acceptable. If
it’s omitted or nil, such a silent selection is always
acceptable. If it is non-nil, it should be a function;
select-safe-coding-system calls this function with one
argument, the base coding system of the selected coding system. If
the function returns nil, select-safe-coding-system
rejects the silently selected coding system, and asks the user to
select a coding system from a list of possible candidates.
If the variable select-safe-coding-system-accept-default-p is
non-nil, it should be a function taking a single argument.
It is used in place of accept-default-p, overriding any
value supplied for this argument.
As a final step, before returning the chosen coding system,
select-safe-coding-system checks whether that coding system is
consistent with what would be selected if the contents of the region
were read from a file. (If not, this could lead to data corruption in
a file subsequently re-visited and edited.) Normally,
select-safe-coding-system uses buffer-file-name as the
file for this purpose, but if file is non-nil, it uses
that file instead (this can be relevant for write-region and
similar functions). If it detects an apparent inconsistency,
select-safe-coding-system queries the user before selecting the
coding system.
This variable names the function to be called to request the user to
select a proper coding system for encoding text when the default
coding system for an output operation cannot safely encode that text.
The default value of this variable is select-safe-coding-system.
Emacs primitives that write text to files, such as
write-region, or send text to other processes, such as
process-send-region, normally call the value of this variable,
unless coding-system-for-write is bound to a non-nil
value (see Specifying a Coding System for One Operation).
Here are two functions you can use to let the user specify a coding system, with completion. See 补全.
This function reads a coding system using the minibuffer, prompting with string prompt, and returns the coding system name as a symbol. If the user enters null input, default specifies which coding system to return. It should be a symbol or a string.
This function reads a coding system using the minibuffer, prompting with string prompt, and returns the coding system name as a symbol. If the user tries to enter null input, it asks the user to try again. See Coding Systems.
This section describes variables that specify the default coding system for certain files or when running certain subprograms, and the function that I/O operations use to access them.
The idea of these variables is that you set them once and for all to the
defaults you want, and then do not change them again. To specify a
particular coding system for a particular operation in a Lisp program,
don’t change these variables; instead, override them using
coding-system-for-read and coding-system-for-write
(see Specifying a Coding System for One Operation).
This variable is an alist of text patterns and corresponding coding
systems. Each element has the form (regexp
. coding-system); a file whose first few kilobytes match
regexp is decoded with coding-system when its contents are
read into a buffer. The settings in this alist take priority over
coding: tags in the files and the contents of
file-coding-system-alist (see below). The default value is set
so that Emacs automatically recognizes mail files in Babyl format and
reads them with no code conversions.
This variable is an alist that specifies the coding systems to use for
reading and writing particular files. Each element has the form
(pattern . coding), where pattern is a regular
expression that matches certain file names. The element applies to file
names that match pattern.
The CDR of the element, coding, should be either a coding system, a cons cell containing two coding systems, or a function name (a symbol with a function definition). If coding is a coding system, that coding system is used for both reading the file and writing it. If coding is a cons cell containing two coding systems, its CAR specifies the coding system for decoding, and its CDR specifies the coding system for encoding.
If coding is a function name, the function should take one
argument, a list of all arguments passed to
find-operation-coding-system. It must return a coding system
or a cons cell containing two coding systems. This value has the same
meaning as described above.
If coding (or what returned by the above function) is
undecided, the normal code-detection is performed.
This variable is an alist that specifies the coding systems to use for
reading and writing particular files. Its form is like that of
file-coding-system-alist, but, unlike the latter, this variable
takes priority over any coding: tags in the file.
This variable is an alist specifying which coding systems to use for a
subprocess, depending on which program is running in the subprocess. It
works like file-coding-system-alist, except that pattern is
matched against the program name used to start the subprocess. The coding
system or systems specified in this alist are used to initialize the
coding systems used for I/O to the subprocess, but you can specify
other coding systems later using set-process-coding-system.
Warning: Coding systems such as undecided, which
determine the coding system from the data, do not work entirely reliably
with asynchronous subprocess output. This is because Emacs handles
asynchronous subprocess output in batches, as it arrives. If the coding
system leaves the character code conversion unspecified, or leaves the
end-of-line conversion unspecified, Emacs must try to detect the proper
conversion from one batch at a time, and this does not always work.
Therefore, with an asynchronous subprocess, if at all possible, use a
coding system which determines both the character code conversion and
the end of line conversion—that is, one like latin-1-unix,
rather than undecided or latin-1.
This variable is an alist that specifies the coding system to use for
network streams. It works much like file-coding-system-alist,
with the difference that the pattern in an element may be either a
port number or a regular expression. If it is a regular expression, it
is matched against the network service name used to open the network
stream.
This variable specifies the coding systems to use for subprocess (and network stream) input and output, when nothing else specifies what to do.
The value should be a cons cell of the form (input-coding
. output-coding). Here input-coding applies to input from
the subprocess, and output-coding applies to output to it.
This variable holds a list of functions that try to determine a coding system for a file based on its undecoded contents.
Each function in this list should be written to look at text in the
current buffer, but should not modify it in any way. The buffer will
contain the text of parts of the file. Each function should take one
argument, size, which tells it how many characters to look at,
starting from point. If the function succeeds in determining a coding
system for the file, it should return that coding system. Otherwise,
it should return nil.
Each function can also find the name of the file to which
the buffer’s content belong in the variable
auto-coding-file-name.
The functions in this list could be called either when the file is visited and Emacs wants to decode its contents, and/or when the file’s buffer is about to be saved and Emacs wants to determine how to encode its contents.
If a file has a ‘coding:’ tag, that takes precedence, so these functions won’t be called.
This function tries to determine a suitable coding system for
filename. It examines the buffer visiting the named file, using
the variables documented above in sequence, until it finds a match for
one of the rules specified by these variables. It then returns a cons
cell of the form (coding . source), where
coding is the coding system to use and source is a symbol,
one of auto-coding-alist, auto-coding-regexp-alist,
:coding, or auto-coding-functions, indicating which one
supplied the matching rule. The value :coding means the coding
system was specified by the coding: tag in the file
(see coding tag in The GNU Emacs Manual).
The order of looking for a matching rule is auto-coding-alist
first, then auto-coding-regexp-alist, then the coding:
tag, and lastly auto-coding-functions. If no matching rule was
found, the function returns nil.
The second argument size is the size of text, in characters,
following point. The function examines text only within size
characters after point. Normally, the buffer should be positioned at
the beginning when this function is called, because one of the places
for the coding: tag is the first one or two lines of the file;
in that case, size should be the size of the buffer.
This function returns a suitable coding system for file
filename. It uses find-auto-coding to find the coding
system. If no coding system could be determined, the function returns
nil. The meaning of the argument size is like in
find-auto-coding.
This function returns the coding system to use (by default) for performing operation with arguments. The value has this form:
(decoding-system . encoding-system)
The first element, decoding-system, is the coding system to use for decoding (in case operation does decoding), and encoding-system is the coding system for encoding (in case operation does encoding).
The argument operation is a symbol; it should be one of
write-region, start-process, call-process,
call-process-region, insert-file-contents, or
open-network-stream. These are the names of the Emacs I/O
primitives that can do character code and eol conversion.
The remaining arguments should be the same arguments that might be given
to the corresponding I/O primitive. Depending on the primitive, one
of those arguments is selected as the target. For example, if
operation does file I/O, whichever argument specifies the file
name is the target. For subprocess primitives, the process name is the
target. For open-network-stream, the target is the service name
or port number.
Depending on operation, this function looks up the target in
file-coding-system-alist, process-coding-system-alist,
or network-coding-system-alist. If the target is found in the
alist, find-operation-coding-system returns its association in
the alist; otherwise it returns nil.
If operation is insert-file-contents, the argument
corresponding to the target may be a cons cell of the form
(filename . buffer). In that case, filename
is a file name to look up in file-coding-system-alist, and
buffer is a buffer that contains the file’s contents (not yet
decoded). If file-coding-system-alist specifies a function to
call for this file, and that function needs to examine the file’s
contents (as it usually does), it should examine the contents of
buffer instead of reading the file.
You can specify the coding system for a specific operation by binding
the variables coding-system-for-read and/or
coding-system-for-write.
If this variable is non-nil, it specifies the coding system to
use for reading a file, or for input from a synchronous subprocess.
It also applies to any asynchronous subprocess or network stream, but in
a different way: the value of coding-system-for-read when you
start the subprocess or open the network stream specifies the input
decoding method for that subprocess or network stream. It remains in
use for that subprocess or network stream unless and until overridden.
The right way to use this variable is to bind it with let for a
specific I/O operation. Its global value is normally nil, and
you should not globally set it to any other value. Here is an example
of the right way to use the variable:
;; Read the file with no character code conversion.
(let ((coding-system-for-read 'no-conversion))
(insert-file-contents filename))
When its value is non-nil, this variable takes precedence over
all other methods of specifying a coding system to use for input,
including file-coding-system-alist,
process-coding-system-alist and
network-coding-system-alist.
This works much like coding-system-for-read, except that it
applies to output rather than input. It affects writing to files,
as well as sending output to subprocesses and net connections. It
also applies to encoding command-line arguments with which Emacs
invokes subprocesses.
When a single operation does both input and output, as do
call-process-region and start-process, both
coding-system-for-read and coding-system-for-write
affect it.
Binding coding-system-for-write to a non-nil value
prevents output primitives from calling the function specified by
select-safe-coding-system-function (see User-Chosen Coding Systems). This is because C-x RET c
(universal-coding-system-argument) works by binding
coding-system-for-write, and Emacs should obey user selection.
If a Lisp program binds coding-system-for-write to a value that
might not be safe for encoding the text to be written, it can also bind
coding-system-require-warning to a non-nil value, which
will force the output primitives to check the encoding by calling the
value of select-safe-coding-system-function even though
coding-system-for-write is non-nil. Alternatively, call
select-safe-coding-system explicitly before using the specified
encoding.
When this variable is non-nil, no end-of-line conversion is done,
no matter which coding system is specified. This applies to all the
Emacs I/O and subprocess primitives, and to the explicit encoding and
decoding functions (see Explicit Encoding and Decoding).
Sometimes, you need to prefer several coding systems for some
operation, rather than fix a single one. Emacs lets you specify a
priority order for using coding systems. This ordering affects the
sorting of lists of coding systems returned by functions such as
find-coding-systems-region (see Coding Systems in Lisp).
This function returns the list of coding systems in the order of their
current priorities. Optional argument highestp, if
non-nil, means return only the highest priority coding system.
This function puts coding-systems at the beginning of the priority list for coding systems, thus making their priority higher than all the rest.
This macro executes body, like progn does
(see progn), with coding-systems at the front of
the priority list for coding systems. coding-systems should be
a list of coding systems to prefer during execution of body.
All the operations that transfer text in and out of Emacs have the ability to use a coding system to encode or decode the text. You can also explicitly encode and decode text using the functions in this section.
The result of encoding, and the input to decoding, are not ordinary text. They logically consist of a series of byte values; that is, a series of ASCII and eight-bit characters. In unibyte buffers and strings, these characters have codes in the range 0 through #xFF (255). In a multibyte buffer or string, eight-bit characters have character codes higher than #xFF (see Text Representations), but Emacs transparently converts them to their single-byte values when you encode or decode such text.
The usual way to read a file into a buffer as a sequence of bytes, so
you can decode the contents explicitly, is with
insert-file-contents-literally (see 从文件读取);
alternatively, specify a non-nil rawfile argument when
visiting a file with find-file-noselect. These methods result in
a unibyte buffer.
The usual way to use the byte sequence that results from explicitly
encoding text is to copy it to a file or process—for example, to write
it with write-region (see 写入文件), and suppress
encoding by binding coding-system-for-write to
no-conversion.
Here are the functions to perform explicit encoding or decoding. The
encoding functions produce sequences of bytes; the decoding functions
are meant to operate on sequences of bytes. All of these functions
discard text properties. They also set last-coding-system-used
to the precise coding system they used.
This command encodes the text from start to end according
to coding system coding-system. Normally, the encoded text
replaces the original text in the buffer, but the optional argument
destination can change that. If destination is a buffer,
the encoded text is inserted in that buffer after point (point does
not move); if it is t, the command returns the encoded text as
a unibyte string without inserting it.
If encoded text is inserted in some buffer, this command returns the length of the encoded text.
The result of encoding is logically a sequence of bytes, but the buffer remains multibyte if it was multibyte before, and any 8-bit bytes are converted to their multibyte representation (see Text Representations).
Do not use undecided for coding-system when
encoding text, since that may lead to unexpected results. Instead,
use select-safe-coding-system (see select-safe-coding-system) to suggest a suitable encoding,
if there’s no obvious pertinent value for coding-system.
This function encodes the text in string according to coding
system coding-system. It returns a new string containing the
encoded text, except when nocopy is non-nil, in which
case the function may return string itself if the encoding
operation is trivial. The result of encoding is a unibyte string.
This command decodes the text from start to end according
to coding system coding-system. To make explicit decoding
useful, the text before decoding ought to be a sequence of byte
values, but both multibyte and unibyte buffers are acceptable (in the
multibyte case, the raw byte values should be represented as eight-bit
characters). Normally, the decoded text replaces the original text in
the buffer, but the optional argument destination can change
that. If destination is a buffer, the decoded text is inserted
in that buffer after point (point does not move); if it is t,
the command returns the decoded text as a multibyte string without
inserting it.
If decoded text is inserted in some buffer, this command returns the length of the decoded text. If that buffer is a unibyte buffer (see Selecting a Representation), the internal representation of the decoded text (see Text Representations) is inserted into the buffer as individual bytes.
This command puts a charset text property on the decoded text.
The value of the property states the character set used to decode the
original text.
This command detects the encoding of the text if necessary. If
coding-system is undecided, the command detects the
encoding of the text based on the byte sequences it finds in the text,
and also detects the type of end-of-line convention used by the text
(see eol type). If coding-system
is undecided-eol-type, where eol-type is
unix, dos, or mac, then the command detects only
the encoding of the text. Any coding-system that doesn’t
specify eol-type, as in utf-8, causes the command to
detect the end-of-line convention; specify the encoding completely, as
in utf-8-unix, if the EOL convention used by the text is known
in advance, to prevent any automatic detection.
This function decodes the text in string according to
coding-system. It returns a new string containing the decoded
text, except when nocopy is non-nil, in which case the
function may return string itself if the decoding operation is
trivial. To make explicit decoding useful, the contents of
string ought to be a unibyte string with a sequence of byte
values, but a multibyte string is also acceptable (assuming it
contains 8-bit bytes in their multibyte form).
This function detects the encoding of the string if needed, like
decode-coding-region does.
If optional argument buffer specifies a buffer, the decoded text is inserted in that buffer after point (point does not move). In this case, the return value is the length of the decoded text. If that buffer is a unibyte buffer, the internal representation of the decoded text is inserted into it as individual bytes.
This function puts a charset text property on the decoded text.
The value of the property states the character set used to decode the
original text:
(decode-coding-string "Gr\374ss Gott" 'latin-1)
⇒ #("Grüss Gott" 0 9 (charset iso-8859-1))
This function decodes the text from from to to as if
it were being read from file filename using insert-file-contents
using the rest of the arguments provided.
The normal way to use this function is after reading text from a file without decoding, if you decide you would rather have decoded it. Instead of deleting the text and reading it again, this time with decoding, you can call this function.
Emacs can use coding systems to decode keyboard input and encode
terminal output. This is useful for terminals that transmit or
display text using a particular encoding, such as Latin-1. Emacs does
not set last-coding-system-used when encoding or decoding
terminal I/O.
This function returns the coding system used for decoding keyboard
input from terminal. A value of no-conversion means no
decoding is done. If terminal is omitted or nil, it
means the selected frame’s terminal. See Multiple Terminals.
This command specifies coding-system as the coding system to use
for decoding keyboard input from terminal. If
coding-system is nil, that means not to decode keyboard
input. If terminal is a frame, it means that frame’s terminal;
if it is nil, that means the currently selected frame’s
terminal. See Multiple Terminals. Note that on modern MS-Windows
systems Emacs always uses Unicode input when decoding keyboard input,
so the encoding set by this command has no effect on Windows.
This function returns the coding system that is in use for encoding
terminal output from terminal. A value of no-conversion
means no encoding is done. If terminal is a frame, it means
that frame’s terminal; if it is nil, that means the currently
selected frame’s terminal.
This command specifies coding-system as the coding system to use
for encoding terminal output from terminal. If
coding-system is nil, that means not to encode terminal
output. If terminal is a frame, it means that frame’s terminal;
if it is nil, that means the currently selected frame’s
terminal.
Input methods provide convenient ways of entering non-ASCII characters from the keyboard. Unlike coding systems, which translate non-ASCII characters to and from encodings meant to be read by programs, input methods provide human-friendly commands. (See Input Methods in The GNU Emacs Manual, for information on how users use input methods to enter text.) How to define input methods is not yet documented in this manual, but here we describe how to use them.
Each input method has a name, which is currently a string; in the future, symbols may also be usable as input method names.
This variable holds the name of the input method now active in the
current buffer. (It automatically becomes local in each buffer when set
in any fashion.) It is nil if no input method is active in the
buffer now.
This variable holds the default input method for commands that choose an
input method. Unlike current-input-method, this variable is
normally global.
This command activates input method input-method for the current
buffer. It also sets default-input-method to input-method.
If input-method is nil, this command deactivates any input
method for the current buffer.
This function reads an input method name with the minibuffer, prompting
with prompt. If default is non-nil, that is returned
by default, if the user enters empty input. However, if
inhibit-null is non-nil, empty input signals an error.
The returned value is a string.
This variable defines all the supported input methods. Each element defines one input method, and should have the form:
(input-method language-env activate-func title description args...)
Here input-method is the input method name, a string; language-env is another string, the name of the language environment this input method is recommended for. (That serves only for documentation purposes.)
activate-func is a function to call to activate this method. The args, if any, are passed as arguments to activate-func. All told, the arguments to activate-func are input-method and the args.
title is a string to display in the mode line while this method is active. description is a string describing this method and what it is good for.
The fundamental interface to input methods is through the
variable input-method-function. See 读取单个事件,
and 调用输入法.
In POSIX, locales control which language to use in language-related features. These Emacs variables control how Emacs interacts with these features.
This variable specifies the coding system to use for decoding system
error messages and—on X Window system only—keyboard input, for
sending batch output to the standard output and error streams, for
encoding the format argument to format-time-string, and for
decoding the return value of format-time-string.
This variable specifies the locale to use for generating system error
messages. Changing the locale can cause messages to come out in a
different language or in a different orthography. If the variable is
nil, the locale is specified by environment variables in the
usual POSIX fashion.
This variable specifies the locale to use for formatting time values.
Changing the locale can cause messages to appear according to the
conventions of a different language. If the variable is nil, the
locale is specified by environment variables in the usual POSIX fashion.
This function returns locale data item for the current POSIX locale, if available. item should be one of these symbols:
codesetReturn the character set as a string (locale item CODESET).
daysReturn a 7-element vector of day names (locale items
DAY_1 through DAY_7);
monthsReturn a 12-element vector of month names (locale items MON_1
through MON_12).
paperReturn a list (width height) of 2 integers, for
the default paper size measured in millimeters (locale items
_NL_PAPER_WIDTH and _NL_PAPER_HEIGHT).
If the system can’t provide the requested information, or if
item is not one of those symbols, the value is nil. All
strings in the return value are decoded using
locale-coding-system. See Locales in The GNU Libc Manual,
for more information about locales and locale items.
GNU Emacs provides two ways to search through a buffer for specified text: exact string searches and regular expression searches. After a regular expression search, you can examine the match data to determine which text matched the whole regular expression or various portions of it.
The ‘skip-chars…’ functions also perform a kind of searching. See Skipping Characters. To search for changes in character properties, see Text Property Search Functions.
These are the primitive functions for searching through the text in a
buffer. They are meant for use in programs, but you may call them
interactively. If you do so, they prompt for the search string; the
arguments limit and noerror are nil, and repeat
is 1. For more details on interactive searching, see Searching and Replacement in The GNU Emacs Manual.
These search functions convert the search string to multibyte if the buffer is multibyte; they convert the search string to unibyte if the buffer is unibyte. See Text Representations.
This function searches forward from point for an exact match for string. If successful, it sets point to the end of the occurrence found, and returns the new value of point. If no match is found, the value and side effects depend on noerror (see below).
In the following example, point is initially at the beginning of the
line. Then (search-forward "fox") moves point after the last
letter of ‘fox’:
---------- Buffer: foo ---------- ∗The quick brown fox jumped over the lazy dog. ---------- Buffer: foo ----------
(search-forward "fox")
⇒ 20
---------- Buffer: foo ----------
The quick brown fox∗ jumped over the lazy dog.
---------- Buffer: foo ----------
The argument limit specifies the bound to the search, and should
be a position in the current buffer. No match extending after
that position is accepted. If limit is omitted or nil, it
defaults to the end of the accessible portion of the buffer.
What happens when the search fails depends on the value of
noerror. If noerror is nil, a search-failed
error is signaled. If noerror is t, search-forward
returns nil and does nothing. If noerror is neither
nil nor t, then search-forward moves point to the
upper bound and returns nil.
The argument noerror only affects valid searches which fail to find a match. Invalid arguments cause errors regardless of noerror.
If count is a positive number n, the search is done n times; each successive search starts at the end of the previous match. If all these successive searches succeed, the function call succeeds, moving point and returning its new value. Otherwise the function call fails, with results depending on the value of noerror, as described above. If count is a negative number −n, the search is done n times in the opposite (backward) direction.
This function searches backward from point for string. It is
like search-forward, except that it searches backwards rather
than forwards. Backward searches leave point at the beginning of the
match.
This function searches forward from point for a word match for string. If it finds a match, it sets point to the end of the match found, and returns the new value of point.
Word matching regards string as a sequence of words, disregarding punctuation that separates them. It searches the buffer for the same sequence of words. Each word must be distinct in the buffer (searching for the word ‘ball’ does not match the word ‘balls’), but the details of punctuation and spacing are ignored (searching for ‘ball boy’ does match ‘ball. Boy!’).
In this example, point is initially at the beginning of the buffer; the search leaves it between the ‘y’ and the ‘!’.
---------- Buffer: foo ---------- ∗He said "Please! Find the ball boy!" ---------- Buffer: foo ----------
(word-search-forward "Please find the ball, boy.")
⇒ 39
---------- Buffer: foo ----------
He said "Please! Find
the ball boy∗!"
---------- Buffer: foo ----------
If limit is non-nil, it must be a position in the current
buffer; it specifies the upper bound to the search. The match found
must not extend after that position.
If noerror is nil, then word-search-forward signals
an error if the search fails. If noerror is t, then it
returns nil instead of signaling an error. If noerror is
neither nil nor t, it moves point to limit (or the
end of the accessible portion of the buffer) and returns nil.
If count is a positive number, it specifies how many successive occurrences to search for. Point is positioned at the end of the last match. If count is a negative number, the search is backward and point is positioned at the beginning of the last match.
Internally, word-search-forward and related functions use the
function word-search-regexp to convert string to a
regular expression that ignores punctuation.
This command is identical to word-search-forward, except that
the beginning or the end of string need not match a word
boundary, unless string begins or ends in whitespace.
For instance, searching for ‘ball boy’ matches ‘ball boyee’,
but does not match ‘balls boy’.
This function searches backward from point for a word match to
string. This function is just like word-search-forward
except that it searches backward and normally leaves point at the
beginning of the match.
This command is identical to word-search-backward, except that
the beginning or the end of string need not match a word
boundary, unless string begins or ends in whitespace.
By default, searches in Emacs ignore the case of the text they are searching through; if you specify searching for ‘FOO’, then ‘Foo’ or ‘foo’ is also considered a match. This applies to regular expressions, too; thus, ‘[aB]’ would match ‘a’ or ‘A’ or ‘b’ or ‘B’.
If you do not want this feature, set the variable
case-fold-search to nil. Then all letters must match
exactly, including case. This is a buffer-local variable; altering the
variable affects only the current buffer. (See 缓冲区局部变量简介.) Alternatively, you may change the default value.
In Lisp code, you will more typically use let to bind
case-fold-search to the desired value.
Note that the user-level incremental search feature handles case distinctions differently. When the search string contains only lower case letters, the search ignores case, but when the search string contains one or more upper case letters, the search becomes case-sensitive. But this has nothing to do with the searching functions used in Lisp code. See Incremental Search in The GNU Emacs Manual.
This buffer-local variable determines whether searches should ignore
case. If the variable is nil they do not ignore case; otherwise
(and by default) they do ignore case.
This variable determines whether the higher-level replacement
functions should preserve case. If the variable is nil, that
means to use the replacement text verbatim. A non-nil value
means to convert the case of the replacement text according to the
text being replaced.
This variable is used by passing it as an argument to the function
replace-match. See Replacing the Text that Matched.
A regular expression, or regexp for short, is a pattern that denotes a (possibly infinite) set of strings. Searching for matches for a regexp is a very powerful operation. This section explains how to write regexps; the following section says how to search for them.
For interactive development of regular expressions, you can use the M-x re-builder command. It provides a convenient interface for creating regular expressions, by giving immediate visual feedback in a separate buffer. As you edit the regexp, all its matches in the target buffer are highlighted. Each parenthesized sub-expression of the regexp is shown in a distinct face, which makes it easier to verify even very complex regexps.
Note that by default Emacs search ignores case (see Searching and Case). To enable case-sensitive regexp search and match, bind
case-fold-search to nil around the code you want to be
case-sensitive.
rx Structured Regexp NotationRegular expressions have a syntax in which a few characters are special constructs and the rest are ordinary. An ordinary character is a simple regular expression that matches that character and nothing else. The special characters are ‘.’, ‘*’, ‘+’, ‘?’, ‘[’, ‘^’, ‘$’, and ‘\’; no new special characters will be defined in the future. The character ‘]’ is special if it ends a bracket expression (see later). The character ‘-’ is special inside a bracket expression. A ‘[:’ and balancing ‘:]’ enclose a character class inside a bracket expression. Any other character appearing in a regular expression is ordinary, unless a ‘\’ precedes it.
For example, ‘f’ is not a special character, so it is ordinary, and therefore ‘f’ is a regular expression that matches the string ‘f’ and no other string. (It does not match the string ‘fg’, but it does match a part of that string.) Likewise, ‘o’ is a regular expression that matches only ‘o’.
Any two regular expressions a and b can be concatenated. The result is a regular expression that matches a string if a matches some amount of the beginning of that string and b matches the rest of the string.
As a simple example, we can concatenate the regular expressions ‘f’ and ‘o’ to get the regular expression ‘fo’, which matches only the string ‘fo’. Still trivial. To do something more powerful, you need to use one of the special regular expression constructs.
Here is a list of the characters that are special in a regular expression.
is a special character that matches any single character except a newline. Using concatenation, we can make regular expressions like ‘a.b’, which matches any three-character string that begins with ‘a’ and ends with ‘b’.
is not a construct by itself; it is a postfix operator that means to match the preceding regular expression repetitively as many times as possible. Thus, ‘o*’ matches any number of ‘o’s (including no ‘o’s).
‘*’ always applies to the smallest possible preceding expression. Thus, ‘fo*’ has a repeating ‘o’, not a repeating ‘fo’. It matches ‘f’, ‘fo’, ‘foo’, and so on.
The matcher processes a ‘*’ construct by matching, immediately, as many repetitions as can be found. Then it continues with the rest of the pattern. If that fails, backtracking occurs, discarding some of the matches of the ‘*’-modified construct in the hope that this will make it possible to match the rest of the pattern. For example, in matching ‘ca*ar’ against the string ‘caaar’, the ‘a*’ first tries to match all three ‘a’s; but the rest of the pattern is ‘ar’ and there is only ‘r’ left to match, so this try fails. The next alternative is for ‘a*’ to match only two ‘a’s. With this choice, the rest of the regexp matches successfully.
is a postfix operator, similar to ‘*’ except that it must match the preceding expression at least once. So, for example, ‘ca+r’ matches the strings ‘car’ and ‘caaaar’ but not the string ‘cr’, whereas ‘ca*r’ matches all three strings.
is a postfix operator, similar to ‘*’ except that it must match the preceding expression either once or not at all. For example, ‘ca?r’ matches ‘car’ or ‘cr’; nothing else.
are non-greedy variants of the operators ‘*’, ‘+’ and ‘?’. Where those operators match the largest possible substring (consistent with matching the entire containing expression), the non-greedy variants match the smallest possible substring (consistent with matching the entire containing expression).
For example, the regular expression ‘c[ad]*a’ when applied to the string ‘cdaaada’ matches the whole string; but the regular expression ‘c[ad]*?a’, applied to that same string, matches just ‘cda’. (The smallest possible match here for ‘[ad]*?’ that permits the whole expression to match is ‘d’.)
is a bracket expression (a.k.a. character alternative), which begins with ‘[’ and is terminated by ‘]’. In the simplest case, the characters between the two brackets are what this bracket expression can match.
Thus, ‘[ad]’ matches either one ‘a’ or one ‘d’, and ‘[ad]*’ matches any string composed of just ‘a’s and ‘d’s (including the empty string). It follows that ‘c[ad]*r’ matches ‘cr’, ‘car’, ‘cdr’, ‘caddaar’, etc.
You can also include character ranges in a bracket expression, by writing the starting and ending characters with a ‘-’ between them. Thus, ‘[a-z]’ matches any lower-case ASCII letter. Ranges may be intermixed freely with individual characters, as in ‘[a-z$%.]’, which matches any lower case ASCII letter or ‘$’, ‘%’ or period. However, the ending character of one range should not be the starting point of another one; for example, ‘[a-m-z]’ should be avoided.
A bracket expression can also specify named character classes (see Character Classes). For example, ‘[[:ascii:]]’ matches any ASCII character. Using a character class is equivalent to mentioning each of the characters in that class; but the latter is not feasible in practice, since some classes include thousands of different characters. A character class should not appear as the lower or upper bound of a range.
The usual regexp special characters are not special inside a bracket expression. A completely different set of characters is special: ‘]’, ‘-’ and ‘^’. To include ‘]’ in a bracket expression, put it at the beginning. To include ‘^’, put it anywhere but at the beginning. To include ‘-’, put it at the end. Thus, ‘[]^-]’ matches all three of these special characters. You cannot use ‘\’ to escape these three characters, since ‘\’ is not special here.
The following aspects of ranges are specific to Emacs, in that POSIX allows but does not require this behavior and programs other than Emacs may behave differently:
case-fold-search is non-nil, ‘[a-z]’ also
matches upper-case letters.
Some kinds of bracket expressions are not the best style even though they have a well-defined meaning in Emacs. They include:
‘[^’ begins a complemented bracket expression, or complemented character alternative. This matches any character except the ones specified. Thus, ‘[^a-z0-9A-Z]’ matches all characters except ASCII letters and digits.
‘^’ is not special in a bracket expression unless it is the first character. The character following the ‘^’ is treated as if it were first (in other words, ‘-’ and ‘]’ are not special there).
A complemented bracket expression can match a newline, unless newline is
mentioned as one of the characters not to match. This is in contrast to
the handling of regexps in programs such as grep.
You can specify named character classes, just like in bracket expressions. For instance, ‘[^[:ascii:]]’ matches any non-ASCII character. See Character Classes.
When matching a buffer, ‘^’ matches the empty string, but only at the beginning of a line in the text being matched (or the beginning of the accessible portion of the buffer). Otherwise it fails to match anything. Thus, ‘^foo’ matches a ‘foo’ that occurs at the beginning of a line.
When matching a string instead of a buffer, ‘^’ matches at the beginning of the string or after a newline character.
For historical compatibility, ‘^’ is special only at the beginning of the regular expression, or after ‘\(’, ‘\(?:’ or ‘\|’. Although ‘^’ is an ordinary character in other contexts, it is good practice to use ‘\^’ even then.
is similar to ‘^’ but matches only at the end of a line (or the end of the accessible portion of the buffer). Thus, ‘x+$’ matches a string of one ‘x’ or more at the end of a line.
When matching a string instead of a buffer, ‘$’ matches at the end of the string or before a newline character.
For historical compatibility, ‘$’ is special only at the end of the regular expression, or before ‘\)’ or ‘\|’. Although ‘$’ is an ordinary character in other contexts, it is good practice to use ‘\$’ even then.
has two functions: it quotes the special characters (including ‘\’), and it introduces additional special constructs.
Because ‘\’ quotes special characters, ‘\$’ is a regular expression that matches only ‘$’, and ‘\[’ is a regular expression that matches only ‘[’, and so on.
Note that ‘\’ also has special meaning in the read syntax of Lisp
strings (see 字符串类型), and must be quoted with ‘\’. For
example, the regular expression that matches the ‘\’ character is
‘\\’. To write a Lisp string that contains the characters
‘\\’, Lisp syntax requires you to quote each ‘\’ with another
‘\’. Therefore, the read syntax for a regular expression matching
‘\’ is "\\\\".
For historical compatibility, a repetition operator is treated as ordinary if it appears at the start of a regular expression or after ‘^’, ‘\`’, ‘\(’, ‘\(?:’ or ‘\|’. For example, ‘*foo’ is treated as ‘\*foo’, and ‘two\|^\{2\}’ is treated as ‘two\|^{2}’. It is poor practice to depend on this behavior; use proper backslash escaping anyway, regardless of where the repetition operator appears.
As a ‘\’ is not special inside a bracket expression, it can
never remove the special meaning of ‘-’, ‘^’ or ‘]’.
You should not quote these characters when they have no special
meaning. This would not clarify anything, since backslashes
can legitimately precede these characters where they have
special meaning, as in ‘[^\]’ ("[^\\]" for Lisp string
syntax), which matches any single character except a backslash.
In practice, most ‘]’ that occur in regular expressions close a bracket expression and hence are special. However, occasionally a regular expression may try to match a complex pattern of literal ‘[’ and ‘]’. In such situations, it sometimes may be necessary to carefully parse the regexp from the start to determine which square brackets enclose a bracket expression. For example, ‘[^][]]’ consists of the complemented bracket expression ‘[^][]’ (which matches any single character that is not a square bracket), followed by a literal ‘]’.
The exact rules are that at the beginning of a regexp, ‘[’ is special and ‘]’ not. This lasts until the first unquoted ‘[’, after which we are in a bracket expression; ‘[’ is no longer special (except when it starts a character class) but ‘]’ is special, unless it immediately follows the special ‘[’ or that ‘[’ followed by a ‘^’. This lasts until the next special ‘]’ that does not end a character class. This ends the bracket expression and restores the ordinary syntax of regular expressions; an unquoted ‘[’ is special again and a ‘]’ not.
Below is a table of the classes you can use in a bracket expression (see bracket expression), and what they mean. Note that the ‘[’ and ‘]’ characters that enclose the class name are part of the name, so a regular expression using these classes needs one more pair of brackets. For example, a regular expression matching a sequence of one or more letters and digits would be ‘[[:alnum:]]+’, not ‘[:alnum:]+’.
This matches any ASCII character (codes 0–127).
This matches any letter or digit. For multibyte characters, it matches characters whose Unicode ‘general-category’ property (see Character Properties) indicates they are alphabetic or decimal number characters.
This matches any letter. For multibyte characters, it matches characters whose Unicode ‘general-category’ property (see Character Properties) indicates they are alphabetic characters.
This matches horizontal whitespace, as defined by Annex C of the
Unicode Technical Standard #18. In particular, it matches spaces,
tabs, and other characters whose Unicode ‘general-category’
property (see Character Properties) indicates they are spacing
separators. (If you only need to look for ASCII whitespace characters,
we suggest using an explicit set of character alternatives, such as
‘[ \t]’, instead, as it will be faster than
[[:blank:]].)
This matches any character whose code is in the range 0–31.
This matches ‘0’ through ‘9’. Thus, ‘[-+[:digit:]]’ matches any digit, as well as ‘+’ and ‘-’.
This matches graphic characters—everything except spaces, ASCII and non-ASCII control characters, surrogates, and codepoints unassigned by Unicode, as indicated by the Unicode ‘general-category’ property (see Character Properties).
This matches any lower-case letter, as determined by the current case
table (see 大小写转换表). If case-fold-search is
non-nil, this also matches any upper-case letter. Note that a
buffer can have its own local case table different from the default
one.
This matches any multibyte character (see Text Representations).
This matches any non-ASCII character.
This matches any printing character—either spaces or graphic characters matched by ‘[:graph:]’.
This matches any punctuation character. (At present, for multibyte characters, it matches anything that has non-word syntax, and thus its exact definition can vary from one major mode to another, since the syntax of a character depends on the major mode.)
This matches any character that has whitespace syntax (see Table of Syntax Classes). Note that the syntax of a character, and thus which characters are considered “whitespace”, depends on the major mode.
This matches any unibyte character (see Text Representations).
This matches any upper-case letter, as determined by the current case
table (see 大小写转换表). If case-fold-search is
non-nil, this also matches any lower-case letter. Note that a
buffer can have its own local case table different from the default
one.
This matches any character that has word syntax (see Table of Syntax Classes). Note that the syntax of a character, and thus which characters are considered “word-constituent”, depends on the major mode.
This matches the hexadecimal digits: ‘0’ through ‘9’, ‘a’ through ‘f’ and ‘A’ through ‘F’.
The classes ‘[:space:]’, ‘[:word:]’ and ‘[:punct:]’ use the syntax-table of the current buffer but not any overriding syntax text properties (see Syntax Properties).
For the most part, ‘\’ followed by any character matches only that character. However, there are several exceptions: certain sequences starting with ‘\’ that have special meanings. Here is a table of the special ‘\’ constructs.
specifies an alternative. Two regular expressions a and b with ‘\|’ in between form an expression that matches anything that either a or b matches.
Thus, ‘foo\|bar’ matches either ‘foo’ or ‘bar’ but no other string.
‘\|’ applies to the largest possible surrounding expressions. Only a surrounding ‘\( … \)’ grouping can limit the grouping power of ‘\|’.
If you need full backtracking capability to handle multiple uses of ‘\|’, use the POSIX regular expression functions (see Emacs versus POSIX Regular Expressions).
is a postfix operator that repeats the previous pattern exactly m times. Thus, ‘x\{5\}’ matches the string ‘xxxxx’ and nothing else. ‘c[ad]\{3\}r’ matches string such as ‘caaar’, ‘cdddr’, ‘cadar’, and so on.
is a more general postfix operator that specifies repetition with a minimum of m repeats and a maximum of n repeats. If m is omitted, the minimum is 0; if n is omitted, there is no maximum. For both forms, m and n, if specified, may be no larger than 2**16 − 1 .
For example, ‘c[ad]\{1,2\}r’ matches the strings ‘car’,
‘cdr’, ‘caar’, ‘cadr’, ‘cdar’, and ‘cddr’, and
nothing else.
‘\{0,1\}’ or ‘\{,1\}’ is equivalent to ‘?’.
‘\{0,\}’ or ‘\{,\}’ is equivalent to ‘*’.
‘\{1,\}’ is equivalent to ‘+’.
is a grouping construct that serves three purposes:
This last application is not a consequence of the idea of a parenthetical grouping; it is a separate feature that was assigned as a second meaning to the same ‘\( … \)’ construct because, in practice, there was usually no conflict between the two meanings. But occasionally there is a conflict, and that led to the introduction of shy groups.
is the shy group construct. A shy group serves the first two purposes of an ordinary group (controlling the nesting of other operators), but it does not get a number, so you cannot refer back to its value with ‘\digit’. Shy groups are particularly useful for mechanically-constructed regular expressions, because they can be added automatically without altering the numbering of ordinary, non-shy groups.
Shy groups are also called non-capturing or unnumbered groups.
is the explicitly numbered group construct. Normal groups get their number implicitly, based on their position, which can be inconvenient. This construct allows you to force a particular group number. There is no particular restriction on the numbering, e.g., you can have several groups with the same number in which case the last one to match (i.e., the rightmost match) will win. Implicitly numbered groups always get the smallest integer larger than the one of any previous group.
matches the same text that matched the digitth occurrence of a grouping (‘\( … \)’) construct.
In other words, after the end of a group, the matcher remembers the beginning and end of the text matched by that group. Later on in the regular expression you can use ‘\’ followed by digit to match that same text, whatever it may have been.
The strings matching the first nine grouping constructs appearing in the entire regular expression passed to a search or matching function are assigned numbers 1 through 9 in the order that the open parentheses appear in the regular expression. So you can use ‘\1’ through ‘\9’ to refer to the text matched by the corresponding grouping constructs.
For example, ‘\(.*\)\1’ matches any newline-free string that is composed of two identical halves. The ‘\(.*\)’ matches the first half, which may be anything, but the ‘\1’ that follows must match the same exact text.
If a ‘\( … \)’ construct matches more than once (which can happen, for instance, if it is followed by ‘*’), only the last match is recorded.
If a particular grouping construct in the regular expression was never matched—for instance, if it appears inside of an alternative that wasn’t used, or inside of a repetition that repeated zero times—then the corresponding ‘\digit’ construct never matches anything. To use an artificial example, ‘\(foo\(b*\)\|lose\)\2’ cannot match ‘lose’: the second alternative inside the larger group matches it, but then ‘\2’ is undefined and can’t match anything. But it can match ‘foobb’, because the first alternative matches ‘foob’ and ‘\2’ matches ‘b’.
matches any word-constituent character. The editor syntax table determines which characters these are. See Syntax Tables.
matches any character that is not a word constituent.
matches any character whose syntax is code. Here code is a character that represents a syntax code: thus, ‘w’ for word constituent, ‘-’ for whitespace, ‘(’ for open parenthesis, etc. To represent whitespace syntax, use either ‘-’ or a space character. See Table of Syntax Classes, for a list of syntax codes and the characters that stand for them.
matches any character whose syntax is not code.
matches any character whose category is code. Here code
is a character that represents a category: for example, in the standard
category table, ‘c’ stands for Chinese characters and ‘g’
stands for Greek characters. You can see the list of all the
currently defined categories with M-x describe-categories RET. You can also define your own categories in addition to
the standard ones using the define-category function
(see Categories).
matches any character whose category is not code.
The following regular expression constructs match the empty string—that is, they don’t consume any characters—but whether they match depends on the context. For all, the beginning and end of the accessible portion of the buffer are treated as if they were the actual beginning and end of the buffer.
matches the empty string, but only at the beginning of the buffer or string being matched against.
matches the empty string, but only at the end of the buffer or string being matched against.
matches the empty string, but only at point. (This construct is not defined when matching against a string.)
matches the empty string, but only at the beginning or end of a word. Thus, ‘\bfoo\b’ matches any occurrence of ‘foo’ as a separate word. ‘\bballs?\b’ matches ‘ball’ or ‘balls’ as a separate word.
‘\b’ matches at the beginning or end of the buffer (or string) regardless of what text appears next to it.
matches the empty string, but not at the beginning or end of a word, nor at the beginning or end of the buffer (or string).
matches the empty string, but only at the beginning of a word. ‘\<’ matches at the beginning of the buffer (or string) only if a word-constituent character follows.
matches the empty string, but only at the end of a word. ‘\>’ matches at the end of the buffer (or string) only if the contents end with a word-constituent character.
matches the empty string, but only at the beginning of a symbol. A symbol is a sequence of one or more word or symbol constituent characters. ‘\_<’ matches at the beginning of the buffer (or string) only if a symbol-constituent character follows.
matches the empty string, but only at the end of a symbol. ‘\_>’ matches at the end of the buffer (or string) only if the contents end with a symbol-constituent character.
Not every string is a valid regular expression. For example, a string
that ends inside a bracket expression without a terminating ‘]’
is invalid, and so is a string that ends with a single ‘\’. If
an invalid regular expression is passed to any of the search functions,
an invalid-regexp error is signaled.
Here is a complicated regexp which was formerly used by Emacs to
recognize the end of a sentence together with any whitespace that
follows. (Nowadays Emacs uses a similar but more complex default
regexp constructed by the function sentence-end.
See Standard Regular Expressions Used in Editing.)
Below, we show first the regexp as a string in Lisp syntax (to distinguish spaces from tab characters), and then the result of evaluating it. The string constant begins and ends with a double-quote. ‘\"’ stands for a double-quote as part of the string, ‘\\’ for a backslash as part of the string, ‘\t’ for a tab and ‘\n’ for a newline.
"[.?!][]\"')}]*\\($\\| $\\|\t\\| \\)[ \t\n]*"
⇒ "[.?!][]\"')}]*\\($\\| $\\| \\| \\)[
]*"
In the output, tab and newline appear as themselves.
This regular expression contains four parts in succession and can be deciphered as follows:
[.?!]The first part of the pattern is a bracket expression that matches any one of three characters: period, question mark, and exclamation mark. The match must begin with one of these three characters. (This is one point where the new default regexp used by Emacs differs from the old. The new value also allows some non-ASCII characters that end a sentence without any following whitespace.)
[]\"')}]*The second part of the pattern matches any closing braces and quotation
marks, zero or more of them, that may follow the period, question mark
or exclamation mark. The \" is Lisp syntax for a double-quote in
a string. The ‘*’ at the end indicates that the immediately
preceding regular expression (a bracket expression, in this case) may be
repeated zero or more times.
\\($\\| $\\|\t\\| \\)The third part of the pattern matches the whitespace that follows the end of a sentence: the end of a line (optionally with a space), or a tab, or two spaces. The double backslashes mark the parentheses and vertical bars as regular expression syntax; the parentheses delimit a group and the vertical bars separate alternatives. The dollar sign is used to match the end of a line.
[ \t\n]*Finally, the last part of the pattern matches any additional whitespace beyond the minimum needed to end a sentence.
In the rx notation (see The rx Structured Regexp Notation), the regexp could be written
(rx (any ".?!") ; Punctuation ending sentence.
(zero-or-more (any "\"')]}")) ; Closing quotes or brackets.
(or line-end
(seq " " line-end)
"\t"
" ") ; Two spaces.
(zero-or-more (any "\t\n "))) ; Optional extra whitespace.
Since rx regexps are just S-expressions, they can be formatted
and commented as such.
rx Structured Regexp Notation ¶As an alternative to the string-based syntax, Emacs provides the
structured rx notation based on Lisp S-expressions. This
notation is usually easier to read, write and maintain than regexp
strings, and can be indented and commented freely. It requires a
conversion into string form since that is what regexp functions
expect, but that conversion typically takes place during
byte-compilation rather than when the Lisp code using the regexp is
run.
Here is an rx regexp27 that matches a block comment in the C
programming language:
(rx "/*" ; Initial /*
(zero-or-more
(or (not "*") ; Either non-*,
(seq "*" ; or * followed by
(not "/")))) ; non-/
(one-or-more "*") ; At least one star,
"/") ; and the final /
or, using shorter synonyms and written more compactly,
(rx "/*"
(* (| (not "*")
(: "*" (not "/"))))
(+ "*") "/")
In conventional string syntax, it would be written
"/\\*\\(?:[^*]\\|\\*[^/]\\)*\\*+/"
The rx notation is mainly useful in Lisp code; it cannot be
used in most interactive situations where a regexp is requested, such
as when running query-replace-regexp or in variable
customization.
rx regexps ¶The various forms in rx regexps are described below. The
shorthand rx represents any rx form. rx…
means zero or more rx forms and, unless stated otherwise,
matches these forms in sequence as if wrapped in a (seq …)
subform.
These are all valid arguments to the rx macro. All forms are
defined by their described semantics; the corresponding string regexps
are provided for ease of understanding only. A, B, …
denote (suitably bracketed) string regexp subexpressions therein.
"some-string"Match the string ‘some-string’ literally. There are no characters with special meaning, unlike in string regexps.
?CMatch the character ‘C’ literally.
(seq rx…) ¶(sequence rx…)(: rx…)(and rx…)Match the rxs in sequence. Without arguments, the expression
matches the empty string.
Corresponding string regexp: ‘AB…’
(subexpressions in sequence).
(or rx…) ¶(| rx…)Match exactly one of the rxs.
If all arguments are strings, characters, or or forms
so constrained, the longest possible match will always be used.
Otherwise, either the longest match or the
first (in left-to-right order) will be used.
Without arguments, the expression will not match anything at all.
Corresponding string regexp: ‘A\|B\|…’.
unmatchable ¶Refuse any match. Equivalent to (or).
See regexp-unmatchable.
Normally, repetition forms are greedy, in that they attempt to match as many times as possible. Some forms are non-greedy; they try to match as few times as possible (see Non-greedy repetition).
(zero-or-more rx…) ¶(0+ rx…)Match the rxs zero or more times. Greedy by default.
Corresponding string regexp: ‘A*’ (greedy),
‘A*?’ (non-greedy)
(one-or-more rx…) ¶(1+ rx…)Match the rxs one or more times. Greedy by default.
Corresponding string regexp: ‘A+’ (greedy),
‘A+?’ (non-greedy)
(zero-or-one rx…) ¶(optional rx…)(opt rx…)Match the rxs once or an empty string. Greedy by default.
Corresponding string regexp: ‘A?’ (greedy),
‘A??’ (non-greedy).
(* rx…) ¶Match the rxs zero or more times. Greedy.
Corresponding string regexp: ‘A*’
(+ rx…) ¶Match the rxs one or more times. Greedy.
Corresponding string regexp: ‘A+’
(? rx…) ¶Match the rxs once or an empty string. Greedy.
Corresponding string regexp: ‘A?’
(*? rx…) ¶Match the rxs zero or more times. Non-greedy.
Corresponding string regexp: ‘A*?’
(+? rx…) ¶Match the rxs one or more times. Non-greedy.
Corresponding string regexp: ‘A+?’
(?? rx…) ¶Match the rxs or an empty string. Non-greedy.
Corresponding string regexp: ‘A??’
(= n rx…)(repeat n rx)Match the rxs exactly n times.
Corresponding string regexp: ‘A\{n\}’
(>= n rx…) ¶Match the rxs n or more times. Greedy.
Corresponding string regexp: ‘A\{n,\}’
(** n m rx…) ¶(repeat n m rx…)Match the rxs at least n but no more than m times. Greedy.
Corresponding string regexp: ‘A\{n,m\}’
The greediness of some repetition forms can be controlled using the following constructs. However, it is usually better to use the explicit non-greedy forms above when such matching is required.
(minimal-match rx) ¶Match rx, with zero-or-more, 0+,
one-or-more, 1+, zero-or-one, opt and
optional using non-greedy matching.
(maximal-match rx) ¶Match rx, with zero-or-more, 0+,
one-or-more, 1+, zero-or-one, opt and
optional using greedy matching. This is the default.
(any set…) ¶(char set…)(in set…)Match a single character from one of the sets. Each set
is a character, a string representing the set of its characters, a
range or a character class (see below). A range is either a
hyphen-separated string like "A-Z", or a cons of characters
like (?A . ?Z).
Note that hyphen (-) is special in strings in this construct,
since it acts as a range separator. To include a hyphen, add it as a
separate character or single-character string.
Corresponding string regexp: ‘[…]’
(not charspec) ¶Match a character not included in charspec. charspec can
be a character, a single-character string, an any, not,
or, intersection, syntax or category form,
or a character class.
If charspec is an or form, its arguments have the same
restrictions as those of intersection; see below.
Corresponding string regexp: ‘[^…]’, ‘\Scode’,
‘\Ccode’
(intersection charset…) ¶Match a character included in all of the charsets.
Each charset can be a character, a single-character string, an
any form without character classes, or an intersection,
or or not form whose arguments are also charsets.
not-newline, nonl ¶Match any character except a newline.
Corresponding string regexp: ‘.’ (dot)
anychar, anything ¶Match any character.
Corresponding string regexp: ‘.\|\n’ (for example)
Match a character from a named character class:
alpha, alphabetic, letterMatch alphabetic characters. More precisely, match characters whose Unicode ‘general-category’ property indicates that they are alphabetic.
alnum, alphanumericMatch alphabetic characters and digits. More precisely, match characters whose Unicode ‘general-category’ property indicates that they are alphabetic or decimal digits.
digit, numeric, numMatch the digits ‘0’–‘9’.
xdigit, hex-digit, hexMatch the hexadecimal digits ‘0’–‘9’, ‘A’–‘F’ and ‘a’–‘f’.
cntrl, controlMatch any character whose code is in the range 0–31.
blankMatch horizontal whitespace. More precisely, match characters whose Unicode ‘general-category’ property indicates that they are spacing separators.
space, whitespace, whiteMatch any character that has whitespace syntax (see Table of Syntax Classes).
lower, lower-caseMatch anything lower-case, as determined by the current case table.
If case-fold-search is non-nil, this also matches any
upper-case letter.
upper, upper-caseMatch anything upper-case, as determined by the current case table.
If case-fold-search is non-nil, this also matches any
lower-case letter.
graph, graphicMatch any character except whitespace, ASCII and non-ASCII control characters, surrogates, and codepoints unassigned by Unicode, as indicated by the Unicode ‘general-category’ property.
print, printingMatch whitespace or a character matched by graph.
punct, punctuationMatch any punctuation character. (At present, for multibyte characters, anything that has non-word syntax.)
word, wordcharMatch any character that has word syntax (see Table of Syntax Classes).
asciiMatch any ASCII character (codes 0–127).
nonasciiMatch any non-ASCII character (but not raw bytes).
The classes space, word and punct use the
syntax-table of the current buffer but not any overriding syntax text
properties (see Syntax Properties).
Corresponding string regexp: ‘[[:class:]]’
(syntax syntax) ¶Match a character with syntax syntax, being one of the following names:
| Syntax name | Syntax character |
|---|---|
whitespace | - |
punctuation | . |
word | w |
symbol | _ |
open-parenthesis | ( |
close-parenthesis | ) |
expression-prefix | ' |
string-quote | " |
paired-delimiter | $ |
escape | \ |
character-quote | / |
comment-start | < |
comment-end | > |
string-delimiter | | |
comment-delimiter | ! |
For details, see Table of Syntax Classes. Please note that
(syntax punctuation) is not equivalent to the character class
punctuation.
Corresponding string regexp: ‘\schar’ where char is the
syntax character.
(category category) ¶Match a character in category category, which is either one of the names below or its category character.
| Category name | Category character |
|---|---|
space-for-indent | space |
base | . |
consonant | 0 |
base-vowel | 1 |
upper-diacritical-mark | 2 |
lower-diacritical-mark | 3 |
tone-mark | 4 |
symbol | 5 |
digit | 6 |
vowel-modifying-diacritical-mark | 7 |
vowel-sign | 8 |
semivowel-lower | 9 |
not-at-end-of-line | < |
not-at-beginning-of-line | > |
alpha-numeric-two-byte | A |
chinese-two-byte | C |
greek-two-byte | G |
japanese-hiragana-two-byte | H |
indian-two-byte | I |
japanese-katakana-two-byte | K |
strong-left-to-right | L |
korean-hangul-two-byte | N |
strong-right-to-left | R |
cyrillic-two-byte | Y |
combining-diacritic | ^ |
ascii | a |
arabic | b |
chinese | c |
ethiopic | e |
greek | g |
korean | h |
indian | i |
japanese | j |
japanese-katakana | k |
latin | l |
lao | o |
tibetan | q |
japanese-roman | r |
thai | t |
vietnamese | v |
hebrew | w |
cyrillic | y |
can-break | | |
For more information about currently defined categories, run the
command M-x describe-categories RET. For how to define
new categories, see Categories.
Corresponding string regexp: ‘\cchar’ where char is the
category character.
These all match the empty string, but only in specific places.
line-start, bol ¶Match at the beginning of a line.
Corresponding string regexp: ‘^’
line-end, eol ¶Match at the end of a line.
Corresponding string regexp: ‘$’
string-start, bos, buffer-start, bot ¶Match at the start of the string or buffer being matched against.
Corresponding string regexp: ‘\`’
string-end, eos, buffer-end, eot ¶Match at the end of the string or buffer being matched against.
Corresponding string regexp: ‘\'’
point ¶Match at point.
Corresponding string regexp: ‘\=’
word-start, bow ¶Match at the beginning of a word.
Corresponding string regexp: ‘\<’
word-end, eow ¶Match at the end of a word.
Corresponding string regexp: ‘\>’
word-boundary ¶Match at the beginning or end of a word.
Corresponding string regexp: ‘\b’
not-word-boundary ¶Match anywhere but at the beginning or end of a word.
Corresponding string regexp: ‘\B’
symbol-start ¶Match at the beginning of a symbol.
Corresponding string regexp: ‘\_<’
symbol-end ¶Match at the end of a symbol.
Corresponding string regexp: ‘\_>’
(group rx…) ¶(submatch rx…)Match the rxs, making the matched text and position accessible
in the match data. The first group in a regexp is numbered 1;
subsequent groups will be numbered one above the previously
highest-numbered group in the pattern so far.
Corresponding string regexp: ‘\(…\)’
(group-n n rx…) ¶(submatch-n n rx…)Like group, but explicitly assign the group number n.
n must be positive.
Corresponding string regexp: ‘\(?n:…\)’
(backref n) ¶Match the text previously matched by group number n.
n must be in the range 1–9.
Corresponding string regexp: ‘\n’
(literal expr) ¶Match the literal string that is the result from evaluating the Lisp expression expr. The evaluation takes place at call time, in the current lexical environment.
(regexp expr) ¶(regex expr)Match the string regexp that is the result from evaluating the Lisp expression expr. The evaluation takes place at call time, in the current lexical environment.
(eval expr) ¶Match the rx form that is the result from evaluating the Lisp
expression expr. The evaluation takes place at macro-expansion
time for rx, at call time for rx-to-string,
in the current global environment.
rx regexps ¶Translate the rx-forms to a string regexp, as if they were the
body of a (seq …) form. The rx macro expands to a
string constant, or, if literal or regexp forms are
used, a Lisp expression that evaluates to a string. Example:
(rx (+ alpha) "=" (+ digit)) ⇒ "[[:alpha:]]+=[[:digit:]]+"
Translate rx-expr to a string regexp which is returned.
If no-group is absent or nil, bracket the result in a
non-capturing group, ‘\(?:…\)’, if necessary to ensure that
a postfix operator appended to it will apply to the whole expression.
Example:
(rx-to-string '(seq (+ alpha) "=" (+ digit)) t) ⇒ "[[:alpha:]]+=[[:digit:]]+"
Arguments to literal and regexp forms in rx-expr
must be string literals.
The pcase macro can use rx expressions as patterns
directly; see rx in pcase.
For mechanisms to add user-defined extensions to the rx
notation, see Defining new rx forms.
rx forms ¶The rx notation can be extended by defining new symbols and
parameterized forms in terms of other rx expressions. This is
handy for sharing parts between several regexps, and for making
complex ones easier to build and understand by putting them together
from smaller pieces.
For example, you could define name to mean
(one-or-more letter), and (quoted x) to mean
(seq ?' x ?') for any x. These forms could then be
used in rx expressions like any other: (rx (quoted name))
would match a nonempty sequence of letters inside single quotes.
The Lisp macros below provide different ways of binding names to definitions. Common to all of them are the following rules:
rx forms, like digit and group, cannot
be redefined.
-regexp to names; they cannot collide with anything else.
rx or
rx-to-string, not merely by their presence in definition
macros. This means that the order of definitions doesn’t matter, even
when they refer to each other, and that syntax errors only show up
when they are used, not when they are defined.
rx
expressions are expected; for example, in the body of a
zero-or-one form, but not inside any or category
forms. They are also allowed inside not and
intersection forms.
Define name globally in all subsequent calls to rx and
rx-to-string. If arglist is absent, then name is
defined as a plain symbol to be replaced with rx-form. Example:
(rx-define haskell-comment (seq "--" (zero-or-more nonl)))
(rx haskell-comment)
⇒ "--.*"
If arglist is present, it must be a list of zero or more
argument names, and name is then defined as a parameterized form.
When used in an rx expression as (name arg…),
each arg will replace the corresponding argument name inside
rx-form.
arglist may end in &rest and one final argument name,
denoting a rest parameter. The rest parameter will expand to all
extra actual argument values not matched by any other parameter in
arglist, spliced into rx-form where it occurs. Example:
(rx-define moan (x y &rest r) (seq x (one-or-more y) r "!"))
(rx (moan "MOO" "A" "MEE" "OW"))
⇒ "MOOA+MEEOW!"
Since the definition is global, it is recommended to give name a package prefix to avoid name clashes with definitions elsewhere, as is usual when naming non-local variables and functions.
Forms defined this way only perform simple template substitution.
For arbitrary computations, use them together with the rx
forms eval, regexp or literal. Example:
(defun n-tuple-rx (n element)
`(seq "<"
(group-n 1 ,element)
,@(mapcar (lambda (i) `(seq ?, (group-n ,i ,element)))
(number-sequence 2 n))
">"))
(rx-define n-tuple (n element) (eval (n-tuple-rx n 'element)))
(rx (n-tuple 3 (+ (in "0-9"))))
⇒ "<\\(?1:[0-9]+\\),\\(?2:[0-9]+\\),\\(?3:[0-9]+\\)>"
Make the rx definitions in bindings available locally for
rx macro invocations in body, which is then evaluated.
Each element of bindings is on the form
(name [arglist] rx-form), where the parts
have the same meaning as in rx-define above. Example:
(rx-let ((comma-separated (item) (seq item (0+ "," item)))
(number (1+ digit))
(numbers (comma-separated number)))
(re-search-forward (rx "(" numbers ")")))
The definitions are only available during the macro-expansion of body, and are thus not present during execution of compiled code.
rx-let can be used not only inside a function, but also at top
level to include global variable and function definitions that need
to share a common set of rx forms. Since the names are local
inside body, there is no need for any package prefixes.
Example:
(rx-let ((phone-number (seq (opt ?+) (1+ (any digit ?-)))))
(defun find-next-phone-number ()
(re-search-forward (rx phone-number)))
(defun phone-number-p (string)
(string-match-p (rx bos phone-number eos) string)))
The scope of the rx-let bindings is lexical, which means that
they are not visible outside body itself, even in functions
called from body.
Evaluate bindings to a list of bindings as in rx-let,
and evaluate body with those bindings in effect for calls
to rx-to-string.
This macro is similar to rx-let, except that the bindings
argument is evaluated (and thus needs to be quoted if it is a list
literal), and the definitions are substituted at run time, which is
required for rx-to-string to work. Example:
(rx-let-eval
'((ponder (x) (seq "Where have all the " x " gone?")))
(looking-at (rx-to-string
'(ponder (or "flowers" "young girls"
"left socks")))))
Another difference from rx-let is that the bindings are
dynamically scoped, and thus also available in functions called from
body. However, they are not visible inside functions defined in
body.
These functions operate on regular expressions.
This function returns a regular expression whose only exact match is
string. Using this regular expression in looking-at will
succeed only if the next characters in the buffer are string;
using it in a search function will succeed if the text being searched
contains string. See Regular Expression Searching.
This allows you to request an exact string match or search when calling a function that wants a regular expression.
(regexp-quote "^The cat$")
⇒ "\\^The cat\\$"
One use of regexp-quote is to combine an exact string match with
context described as a regular expression. For example, this searches
for the string that is the value of string, surrounded by
whitespace:
(re-search-forward (concat "\\s-" (regexp-quote string) "\\s-"))
The returned string may be string itself if it does not contain any special characters.
This function returns an efficient regular expression that will match any of the strings in the list strings. This is useful when you need to make matching or searching as fast as possible—for example, for Font Lock mode28.
If strings is the empty list, the return value is a regexp that never matches anything.
The optional argument paren can be any of the following:
The resulting regexp is preceded by paren and followed by ‘\)’. For example, use ‘"\\(?1:"’ to produce an explicitly numbered group.
wordsThe resulting regexp is surrounded by ‘\<\(’ and ‘\)\>’.
symbolsThe resulting regexp is surrounded by ‘\_<\(’ and ‘\)\_>’ (this is often appropriate when matching programming-language keywords and the like).
nilThe resulting regexp is surrounded by ‘\(’ and ‘\)’.
nilThe resulting regexp is surrounded by ‘\(?:’ and ‘\)’, if it is necessary to ensure that a postfix operator appended to it will apply to the whole expression.
The returned regexp is ordered in such a way that it will always match the longest string possible.
Up to reordering, the resulting regexp of regexp-opt is
equivalent to but usually more efficient than that of a simplified
version:
(defun simplified-regexp-opt (strings &optional paren)
(let ((parens
(cond
((stringp paren) (cons paren "\\)"))
((eq paren 'words) '("\\<\\(" . "\\)\\>"))
((eq paren 'symbols) '("\\_<\\(" . "\\)\\_>"))
((null paren) '("\\(?:" . "\\)"))
(t '("\\(" . "\\)")))))
(concat (car parens)
(mapconcat 'regexp-quote strings "\\|")
(cdr parens))))
This function returns the total number of grouping constructs (parenthesized expressions) in regexp. This does not include shy groups (see Backslash Constructs in Regular Expressions).
This function returns a regular expression matching a character in the list of characters chars.
(regexp-opt-charset '(?a ?b ?c ?d ?e))
⇒ "[a-e]"
This variable contains a regexp that is guaranteed not to match any string at all. It is particularly useful as default value for variables that may be set to a pattern that actually matches something.
The Emacs regexp implementation, like many of its kind, is generally robust but occasionally causes trouble in either of two ways: matching may run out of internal stack space and signal an error, and it can take a long time to complete. The advice below will make these symptoms less likely and help alleviate problems that do arise.
\`). This takes advantage
of fast paths in the implementation and can avoid futile matching
attempts. Other zero-width assertions may also bring benefits by
causing a match to fail early.
(It is a trade-off: successfully matched or-patterns run faster with the most frequently matched pattern first.)
Be especially careful with nested repetitions: they can easily result in very slow matching in the presence of ambiguities. For example, ‘\(?:a*b*\)+c’ will take a long time attempting to match even a moderately long string of ‘a’s before failing. The equivalent ‘\(?:a\|b\)*c’ is much faster, and ‘[ab]*c’ better still.
rx (see The rx Structured Regexp Notation); it can optimize some
or-patterns automatically and will never introduce capturing groups
unless explicitly requested.
If you run into regexp stack overflow despite following the above advice, don’t be afraid of performing the matching in multiple function calls, each using a simpler regexp where backtracking can more easily be contained.
To help diagnose problems in your regexps or in the regexp engine
itself, this function returns a string describing the compiled
form of regexp. To make sense of it, it can be necessary
to read at least the description of the re_opcode_t type in the
src/regex-emacs.c file in Emacs’s source code.
It is currently able to give a meaningful description only if Emacs
was compiled with --enable-checking.
In GNU Emacs, you can search for the next match for a regular
expression (see Syntax of Regular Expressions) either incrementally or not.
For incremental search commands, see Regular
Expression Search in The GNU Emacs Manual. Here we describe
only the search functions useful in programs. The principal one is
re-search-forward.
These search functions convert the regular expression to multibyte if the buffer is multibyte; they convert the regular expression to unibyte if the buffer is unibyte. See Text Representations.
This function searches forward in the current buffer for a string of text that is matched by the regular expression regexp. The function skips over any amount of text that is not matched by regexp, and leaves point at the end of the first match found. It returns the new value of point.
If limit is non-nil, it must be a position in the current
buffer. It specifies the upper bound to the search. No match
extending after that position is accepted. If limit is omitted
or nil, it defaults to the end of the accessible portion of the
buffer.
What re-search-forward does when the search fails depends on
the value of noerror:
nilSignal a search-failed error.
tDo nothing and return nil.
Move point to limit (or the end of the accessible portion of the
buffer) and return nil.
The argument noerror only affects valid searches which fail to find a match. Invalid arguments cause errors regardless of noerror.
If count is a positive number n, the search is done n times; each successive search starts at the end of the previous match. If all these successive searches succeed, the function call succeeds, moving point and returning its new value. Otherwise the function call fails, with results depending on the value of noerror, as described above. If count is a negative number −n, the search is done n times in the opposite (backward) direction.
In the following example, point is initially before the ‘T’. Evaluating the search call moves point to the end of that line (between the ‘t’ of ‘hat’ and the newline).
---------- Buffer: foo ---------- I read "∗The cat in the hat comes back" twice. ---------- Buffer: foo ----------
(re-search-forward "[a-z]+" nil t 5)
⇒ 27
---------- Buffer: foo ----------
I read "The cat in the hat∗
comes back" twice.
---------- Buffer: foo ----------
This function searches backward in the current buffer for a string of text that is matched by the regular expression regexp, leaving point at the beginning of the first text found.
This function is analogous to re-search-forward, but they are not
simple mirror images. re-search-forward finds the match whose
beginning is as close as possible to the starting point. If
re-search-backward were a perfect mirror image, it would find the
match whose end is as close as possible. However, in fact it finds the
match whose beginning is as close as possible (and yet ends before the
starting point). The reason for this is that matching a regular
expression at a given spot always works from beginning to end, and
starts at a specified beginning position.
A true mirror-image of re-search-forward would require a special
feature for matching regular expressions from end to beginning. It’s
not worth the trouble of implementing that.
This function returns the index of the start of the first match for
the regular expression regexp in string, or nil if
there is no match. If start is non-nil, the search starts
at that index in string.
For example,
(string-match
"quick" "The quick brown fox jumped quickly.")
⇒ 4
(string-match
"quick" "The quick brown fox jumped quickly." 8)
⇒ 27
The index of the first character of the string is 0, the index of the second character is 1, and so on.
By default, if this function finds a match, the index of the first
character beyond the match is available as (match-end 0).
See The Match Data. If inhibit-modify is non-nil, the
match data isn’t modified.
(string-match
"quick" "The quick brown fox jumped quickly." 8)
⇒ 27
(match-end 0)
⇒ 32
This predicate function does what string-match does, but it
avoids modifying the match data.
This function determines whether the text in the current buffer directly
following point matches the regular expression regexp. “Directly
following” means precisely that: the search is “anchored” and it can
succeed only starting with the first character following point. The
result is t if so, nil otherwise.
This function does not move point, but it does update the match data
(if inhibit-modify is nil or missing, which is the
default). See The Match Data. As a convenience, instead of using the
inhibit-modify argument, you can use looking-at-p,
described below.
In this example, point is located directly before the ‘T’. If it
were anywhere else, the result would be nil.
---------- Buffer: foo ----------
I read "∗The cat in the hat
comes back" twice.
---------- Buffer: foo ----------
(looking-at "The cat in the hat$")
⇒ t
This function returns t if regexp matches the text
immediately before point (i.e., ending at point), and nil otherwise.
Because regular expression matching works only going forward, this is
implemented by searching backwards from point for a match that ends at
point. That can be quite slow if it has to search a long distance.
You can bound the time required by specifying a non-nil value
for limit, which says not to search before limit. In this
case, the match that is found must begin at or after limit.
Here’s an example:
---------- Buffer: foo ----------
I read "∗The cat in the hat
comes back" twice.
---------- Buffer: foo ----------
(looking-back "read \"" 3)
⇒ t
(looking-back "read \"" 4)
⇒ nil
If greedy is non-nil, this function extends the match
backwards as far as possible, stopping when a single additional
previous character cannot be part of a match for regexp. When
the match is extended, its starting position is allowed to occur
before limit.
As a general recommendation, try to avoid using looking-back
wherever possible, since it is slow. For this reason, there are no
plans to add a looking-back-p function.
This predicate function works like looking-at, but without
updating the match data.
If this variable is non-nil, it should be a regular expression
that says how to search for whitespace. In that case, any group of
spaces in a regular expression being searched for stands for use of
this regular expression. However, spaces inside of constructs such as
‘[…]’ and ‘*’, ‘+’, ‘?’ are not affected by
search-spaces-regexp.
Since this variable affects all regular expression search and match constructs, you should bind it temporarily for as small as possible a part of the code, and only where the Lisp code affected by the binding performs searches whose regexp was produced from interactive user input. In other words, this variable should only be used to tell regexp search primitives how to interpret whitespace typed by the user.
The usual regular expression functions do backtracking when necessary to handle the ‘\|’ and repetition constructs, but they continue this only until they find some match. Then they succeed and report the first match found.
This section describes alternative search functions which perform the full backtracking specified by the POSIX standard for regular expression matching. They continue backtracking until they have tried all possibilities and found all matches, so they can report the longest match, as required by POSIX. This is much slower, so use these functions only when you really need the longest match.
Despite their names, the POSIX search and match functions use Emacs regular expressions, not POSIX regular expressions. See Emacs versus POSIX Regular Expressions. Also, they do not properly support the non-greedy repetition operators (see non-greedy). This is because POSIX backtracking conflicts with the semantics of non-greedy repetition.
This is like re-search-forward except that it performs the full
backtracking specified by the POSIX standard for regular expression
matching.
This is like re-search-backward except that it performs the full
backtracking specified by the POSIX standard for regular expression
matching.
This is like looking-at except that it performs the full
backtracking specified by the POSIX standard for regular expression
matching.
This is like string-match except that it performs the full
backtracking specified by the POSIX standard for regular expression
matching.
Emacs keeps track of the start and end positions of the segments of text found during a search; this is called the match data. Thanks to the match data, you can search for a complex pattern, such as a date in a mail message, and then extract parts of the match under control of the pattern.
Because the match data normally describe the most recent search only, you must be careful not to do another search inadvertently between the search you wish to refer back to and the use of the match data. If you can’t avoid another intervening search, you must save and restore the match data around it, to prevent it from being overwritten.
Notice that all functions are allowed to overwrite the match data unless they’re explicitly documented not to do so. A consequence is that functions that are run implicitly in the background (see Timers for Delayed Execution, and Idle Timers) should likely save and restore the match data explicitly.
This function replaces all or part of the text matched by the last search. It works by means of the match data.
This function performs a replacement operation on a buffer or string.
If you did the last search in a buffer, you should omit the
string argument or specify nil for it, and make sure that
the current buffer is the one in which you performed the last search.
Then this function edits the buffer, replacing the matched text with
replacement. It leaves point at the end of the replacement
text.
If you performed the last search on a string, pass the same string as string. Then this function returns a new string, in which the matched text is replaced by replacement.
If fixedcase is non-nil, then replace-match uses
the replacement text without case conversion; otherwise, it converts
the replacement text depending upon the capitalization of the text to
be replaced. If the original text is all upper case, this converts
the replacement text to upper case. If all words of the original text
are capitalized, this capitalizes all the words of the replacement
text. If all the words are one-letter and they are all upper case,
they are treated as capitalized words rather than all-upper-case
words.
If literal is non-nil, then replacement is inserted
exactly as it is, the only alterations being case changes as needed.
If it is nil (the default), then the character ‘\’ is treated
specially. If a ‘\’ appears in replacement, then it must be
part of one of the following sequences:
This stands for the entire text being replaced.
This stands for the text that matched the nth subexpression in the original regexp. Subexpressions are those expressions grouped inside ‘\(…\)’. If the nth subexpression never matched, an empty string is substituted.
This stands for a single ‘\’ in the replacement text.
This stands for itself (for compatibility with replace-regexp
and related commands; see Regexp Replace in The GNU
Emacs Manual).
Any other character following ‘\’ signals an error.
The substitutions performed by ‘\&’ and ‘\n’ occur after case conversion, if any. Therefore, the strings they substitute are never case-converted.
If subexp is non-nil, that says to replace just
subexpression number subexp of the regexp that was matched, not
the entire match. For example, after matching ‘foo \(ba*r\)’,
calling replace-match with 1 as subexp means to replace
just the text that matched ‘\(ba*r\)’.
This function returns the text that would be inserted into the buffer
by replace-match, but without modifying the buffer. It is
useful if you want to present the user with actual replacement result,
with constructs like ‘\n’ or ‘\&’ substituted with
matched groups. Arguments replacement and optional
fixedcase, literal, string and subexp have the
same meaning as for replace-match.
This section explains how to use the match data to find out what was matched by the last search or match operation, if it succeeded.
You can ask about the entire matching text, or about a particular parenthetical subexpression of a regular expression. The count argument in the functions below specifies which. If count is zero, you are asking about the entire match. If count is positive, it specifies which subexpression you want.
Recall that the subexpressions of a regular expression are those expressions grouped with escaped parentheses, ‘\(…\)’. The countth subexpression is found by counting occurrences of ‘\(’ from the beginning of the whole regular expression. The first subexpression is numbered 1, the second 2, and so on. Only regular expressions can have subexpressions—after a simple string search, the only information available is about the entire match.
Every successful search sets the match data. Therefore, you should
query the match data immediately after searching, before calling any
other function that might perform another search. Alternatively, you
may save and restore the match data (see Saving and Restoring the Match Data) around
the call to functions that could perform another search. Or use the
functions that explicitly do not modify the match data;
e.g., string-match-p.
A search which fails may or may not alter the match data. In the current implementation, it does not, but we may change it in the future. Don’t try to rely on the value of the match data after a failing search.
This function returns, as a string, the text matched in the last search or match operation. It returns the entire text if count is zero, or just the portion corresponding to the countth parenthetical subexpression, if count is positive.
If the last such operation was done against a string with
string-match, then you should pass the same string as the
argument in-string. After a buffer search or match,
you should omit in-string or pass nil for it; but you
should make sure that the current buffer when you call
match-string is the one in which you did the searching or
matching. Failure to follow this advice will lead to incorrect results.
The value is nil if count is out of range, or for a
subexpression inside a ‘\|’ alternative that wasn’t used or a
repetition that repeated zero times.
This function is like match-string except that the result
has no text properties.
If the last regular expression search found a match, this function returns the position of the start of the matching text or of a subexpression of it.
If count is zero, then the value is the position of the start of the entire match. Otherwise, count specifies a subexpression in the regular expression, and the value of the function is the starting position of the match for that subexpression.
The value is nil for a subexpression inside a ‘\|’
alternative that wasn’t used or a repetition that repeated zero times.
This function is like match-beginning except that it returns the
position of the end of the match, rather than the position of the
beginning.
Here is an example of using the match data, with a comment showing the positions within the text:
(string-match "\\(qu\\)\\(ick\\)"
"The quick fox jumped quickly.")
;0123456789
⇒ 4
(match-string 0 "The quick fox jumped quickly.")
⇒ "quick"
(match-string 1 "The quick fox jumped quickly.")
⇒ "qu"
(match-string 2 "The quick fox jumped quickly.")
⇒ "ick"
(match-beginning 1) ; The beginning of the match ⇒ 4 ; with ‘qu’ is at index 4.
(match-beginning 2) ; The beginning of the match ⇒ 6 ; with ‘ick’ is at index 6.
(match-end 1) ; The end of the match ⇒ 6 ; with ‘qu’ is at index 6. (match-end 2) ; The end of the match ⇒ 9 ; with ‘ick’ is at index 9.
Here is another example. Point is initially located at the beginning of the line. Searching moves point to between the space and the word ‘in’. The beginning of the entire match is at the 9th character of the buffer (‘T’), and the beginning of the match for the first subexpression is at the 13th character (‘c’).
(list
(re-search-forward "The \\(cat \\)")
(match-beginning 0)
(match-beginning 1))
⇒ (17 9 13)
---------- Buffer: foo ----------
I read "The cat ∗in the hat comes back" twice.
^ ^
9 13
---------- Buffer: foo ----------
(In this case, the index returned is a buffer position; the first character of the buffer counts as 1.)
The functions match-data and set-match-data read or
write the entire match data, all at once.
This function returns a list of positions (markers or integers) that
record all the information on the text that the last search matched.
Element zero is the position of the beginning of the match for the
whole expression; element one is the position of the end of the match
for the expression. The next two elements are the positions of the
beginning and end of the match for the first subexpression, and so on.
In general, element
number 2n
corresponds to (match-beginning n); and
element
number 2n + 1
corresponds to (match-end n).
Normally all the elements are markers or nil, but if
integers is non-nil, that means to use integers instead
of markers. (In that case, the buffer itself is appended as an
additional element at the end of the list, to facilitate complete
restoration of the match data.) If the last match was done on a
string with string-match, then integers are always used,
since markers can’t point into a string.
If reuse is non-nil, it should be a list. In that case,
match-data stores the match data in reuse. That is,
reuse is destructively modified. reuse does not need to
have the right length. If it is not long enough to contain the match
data, it is extended. If it is too long, the length of reuse
stays the same, but the elements that were not used are set to
nil. The purpose of this feature is to reduce the need for
garbage collection.
If reseat is non-nil, all markers on the reuse list
are reseated to point to nowhere.
As always, there must be no possibility of intervening searches between
the call to a search function and the call to match-data that is
intended to access the match data for that search.
(match-data)
⇒ (#<marker at 9 in foo>
#<marker at 17 in foo>
#<marker at 13 in foo>
#<marker at 17 in foo>)
This function sets the match data from the elements of match-list,
which should be a list that was the value of a previous call to
match-data. (More precisely, anything that has the same format
will work.)
If match-list refers to a buffer that doesn’t exist, you don’t get an error; that sets the match data in a meaningless but harmless way.
If reseat is non-nil, all markers on the match-list list
are reseated to point to nowhere.
store-match-data is a semi-obsolete alias for set-match-data.
When you call a function that may search, you may need to save and restore the match data around that call, if you want to preserve the match data from an earlier search for later use. Here is an example that shows the problem that arises if you fail to save the match data:
(re-search-forward "The \\(cat \\)")
⇒ 48
(foo) ; foo does more searching.
(match-end 0)
⇒ 61 ; Unexpected result—not 48!
You can save and restore the match data with save-match-data:
This macro executes body, saving and restoring the match data around it. The return value is the value of the last form in body.
You could use set-match-data together with match-data to
imitate the effect of the special form save-match-data. Here is
how:
(let ((data (match-data)))
(unwind-protect
... ; Ok to change the original match data.
(set-match-data data)))
Emacs automatically saves and restores the match data when it runs process filter functions (see Process Filter Functions) and process sentinels (see Sentinels: Detecting Process Status Changes).
If you want to find all matches for a regexp in part of the buffer
and replace them, the most flexible way is to write an explicit loop
using re-search-forward and replace-match, like this:
(while (re-search-forward "foo[ \t]+bar" nil t) (replace-match "foobar"))
See Replacing the Text that Matched, for a
description of replace-match.
It may be more convenient to limit the replacements to a specific
region. The function replace-regexp-in-region does that.
This function replaces all the occurrences of regexp with
replacement in the region of buffer text between start and
end; start defaults to position of point, and end
defaults to the last accessible position of the buffer. The search
for regexp is case-sensitive, and replacement is inserted
without changing its letter-case. The replacement string can
use the same special elements starting with ‘\’ as
replace-match does. The function returns the number of
replaced occurrences, or nil if regexp is not found. The
function preserves the position of point.
(replace-regexp-in-region "foo[ \t]+bar" "foobar")
This function works similarly to replace-regexp-in-region,
but searches for, and replaces, literal strings instead of
regular expressions.
Emacs also has special functions for replacing matches in a string.
This function copies string and searches it for matches for
regexp, and replaces them with rep. It returns the
modified copy. If start is non-nil, the search for
matches starts at that index in string, and the returned value
does not include the first start characters of string.
To get the whole transformed string, concatenate the first
start characters of string with the return value.
This function uses replace-match to do the replacement, and it
passes the optional arguments fixedcase, literal and
subexp along to replace-match.
Instead of a string, rep can be a function. In that case,
replace-regexp-in-string calls rep for each match,
passing the text of the match as its sole argument. It collects the
value rep returns and passes that to replace-match as the
replacement string. The match data at this point are the result
of matching regexp against a substring of string.
This function replaces all occurrences of from-string with to-string in in-string and returns the result. It may return one of its arguments unchanged, a constant string or a new string. Case is significant, and text properties are ignored.
If you want to write a command along the lines of query-replace,
you can use perform-replace to do the work.
This function is the guts of query-replace and related
commands. It searches for occurrences of from-string in the
text between positions start and end and replaces some or
all of them. If start is nil (or omitted), point is used
instead, and the end of the buffer’s accessible portion is used for
end. (If the optional argument backward is
non-nil, the search starts at end and goes backward.)
If query-flag is nil, it replaces all
occurrences; otherwise, it asks the user what to do about each one.
If regexp-flag is non-nil, then from-string is
considered a regular expression; otherwise, it must match literally. If
delimited-flag is non-nil, then only replacements
surrounded by word boundaries are considered.
The argument replacements specifies what to replace occurrences with. If it is a string, that string is used. It can also be a list of strings, to be used in cyclic order.
If replacements is a cons cell, (function . data), this means to call function after each match to
get the replacement text. This function is called with two arguments:
data, and the number of replacements already made.
If repeat-count is non-nil, it should be an integer. Then
it specifies how many times to use each of the strings in the
replacements list before advancing cyclically to the next one.
If from-string contains upper-case letters, then
perform-replace binds case-fold-search to nil, and
it uses the replacements without altering their case.
Normally, the keymap query-replace-map defines the possible
user responses for queries. The argument map, if
non-nil, specifies a keymap to use instead of
query-replace-map.
Non-nil region-noncontiguous-p means that the region
between start and end is composed of noncontiguous pieces.
The most common example of this is a rectangular region, where the
pieces are separated by newline characters.
This function uses one of two functions to search for the next
occurrence of from-string. These functions are specified by the
values of two variables: replace-re-search-function and
replace-search-function. The former is called when the
argument regexp-flag is non-nil, the latter when it is
nil.
This variable holds a special keymap that defines the valid user
responses for perform-replace and the commands that use it, as
well as y-or-n-p and map-y-or-n-p. This map is unusual
in two ways:
read-key-sequence to get the input; instead, they read a single
event and look it up “by hand”.
Here are the meaningful bindings for query-replace-map.
Several of them are meaningful only for query-replace and
friends.
actDo take the action being considered—in other words, “yes”.
skipDo not take action for this question—in other words, “no”.
exitAnswer this question “no”, and give up on the entire series of questions, assuming that the answers will be “no”.
exit-prefixLike exit, but add the key that was pressed to
unread-command-events (see 事件输入的杂项功能).
act-and-exitAnswer this question “yes”, and give up on the entire series of questions, assuming that subsequent answers will be “no”.
act-and-showAnswer this question “yes”, but show the results—don’t advance yet to the next question.
automaticAnswer this question and all subsequent questions in the series with “yes”, without further user interaction.
backupMove back to the previous place that a question was asked about.
undoUndo last replacement and move back to the place where that replacement was performed.
undo-allUndo all replacements and move back to the place where the first replacement was performed.
editEnter a recursive edit to deal with this question—instead of any other action that would normally be taken.
edit-replacementEdit the replacement for this question in the minibuffer.
delete-and-editDelete the text being considered, then enter a recursive edit to replace it.
recenterscroll-upscroll-downscroll-other-windowscroll-other-window-downPerform the specified window scroll operation, then ask the same
question again. Only y-or-n-p and related functions use this
answer.
quitPerform a quit right away. Only y-or-n-p and related functions
use this answer.
helpDisplay some help, then ask again.
This variable holds a keymap that extends query-replace-map by
providing additional key bindings that are useful in multi-buffer
replacements. The additional bindings are:
automatic-allAnswer this question and all subsequent questions in the series with “yes”, without further user interaction, for all remaining buffers.
exit-currentAnswer this question “no”, and give up on the entire series of questions for the current buffer. Continue to the next buffer in the sequence.
This variable specifies a function that perform-replace calls
to search for the next string to replace. Its default value is
search-forward. Any other value should name a function of 3
arguments: the first 3 arguments of search-forward
(see Searching for Strings).
This variable specifies a function that perform-replace calls
to search for the next regexp to replace. Its default value is
re-search-forward. Any other value should name a function of 3
arguments: the first 3 arguments of re-search-forward
(see Regular Expression Searching).
This section describes some variables that hold regular expressions used for certain purposes in editing:
This is the regular expression describing line-beginnings that separate
pages. The default value is "^\014" (i.e., "^^L" or
"^\C-l"); this matches a line that starts with a formfeed
character.
The following two regular expressions should not assume the match always starts at the beginning of a line; they should not use ‘^’ to anchor the match. Most often, the paragraph commands do check for a match only at the beginning of a line, which means that ‘^’ would be superfluous. When there is a nonzero left margin, they accept matches that start after the left margin. In that case, a ‘^’ would be incorrect. However, a ‘^’ is harmless in modes where a left margin is never used.
This is the regular expression for recognizing the beginning of a line
that separates paragraphs. (If you change this, you may have to
change paragraph-start also.) The default value is
"[ \t\f]*$", which matches a line that consists entirely of
spaces, tabs, and form feeds (after its left margin).
This is the regular expression for recognizing the beginning of a line
that starts or separates paragraphs. The default value is
"\f\\|[ \t]*$", which matches a line containing only
whitespace or starting with a form feed (after its left margin).
If non-nil, the value should be a regular expression describing
the end of a sentence, including the whitespace following the
sentence. (All paragraph boundaries also end sentences, regardless.)
If the value is nil, as it is by default, then the function
sentence-end constructs the regexp. That is why you
should always call the function sentence-end to obtain the
regexp to be used to recognize the end of a sentence.
This function returns the value of the variable sentence-end,
if non-nil. Otherwise it returns a default value based on the
values of the variables sentence-end-double-space
(see Definition of sentence-end-double-space),
sentence-end-without-period, and
sentence-end-without-space.
Regular expression syntax varies significantly among computer programs.
When writing Elisp code that generates regular expressions for use by other
programs, it is helpful to know how syntax variants differ.
To give a feel for the variation, this section discusses how
Emacs regular expressions differ from two syntax variants standarded by POSIX:
basic regular expressions (BREs) and extended regular expressions (EREs).
Plain grep uses BREs, and ‘grep -E’ uses EREs.
Emacs regular expressions have a syntax closer to EREs than to BREs, with some extensions. Here is a summary of how POSIX BREs and EREs differ from Emacs regular expressions.
grep treats ‘\|’ like Emacs does,
but does not support all the Emacs escapes.
grep treats it like Emacs does.
In POSIX EREs, ‘^’ is always special outside of bracket expressions,
which means the ERE ‘x^’ never matches.
In Emacs regular expressions, ‘^’ is special only at the
beginning of the regular expression, or after ‘\(’, ‘\(?:’
or ‘\|’.
grep treats it like Emacs
does. In POSIX EREs, ‘$’ is always special outside of bracket
expressions (see bracket expressions), which means
the ERE ‘$x’ never matches. In Emacs regular expressions,
‘$’ is special only at the end of the regular expression, or
before ‘\)’ or ‘\|’.
A syntax table specifies the syntactic role of each character in a buffer. It can be used to determine where words, symbols, and other syntactic constructs begin and end. This information is used by many Emacs facilities, including Font Lock mode (see Font Lock Mode) and the various complex movement commands (see Motion).
A syntax table is a data structure which can be used to look up the syntax class and other syntactic properties of each character. Syntax tables are used by Lisp programs for scanning and moving across text.
Internally, a syntax table is a char-table (see 字符表).
The element at index c describes the character with code
c; its value is a cons cell which specifies the syntax of the
character in question. See Syntax Table Internals, for details.
However, instead of using aset and aref to modify and
inspect syntax table contents, you should usually use the higher-level
functions char-syntax and modify-syntax-entry, which are
described in Syntax Table Functions.
This function returns t if object is a syntax table.
Each buffer has its own major mode, and each major mode has its own
idea of the syntax class of various characters. For example, in Lisp
mode, the character ‘;’ begins a comment, but in C mode, it
terminates a statement. To support these variations, the syntax table
is local to each buffer. Typically, each major mode has its own
syntax table, which it installs in all buffers that use that mode.
For example, the variable emacs-lisp-mode-syntax-table holds
the syntax table used by Emacs Lisp mode, and
c-mode-syntax-table holds the syntax table used by C mode.
Changing a major mode’s syntax table alters the syntax in all of that
mode’s buffers, as well as in any buffers subsequently put in that
mode. Occasionally, several similar modes share one syntax table.
See 主模式示例, for an example of how to set up a syntax
table.
A syntax table can inherit from another syntax table, which is called its parent syntax table. A syntax table can leave the syntax class of some characters unspecified, by giving them the “inherit” syntax class; such a character then acquires the syntax class specified by the parent syntax table (see Table of Syntax Classes). Emacs defines a standard syntax table, which is the default parent syntax table, and is also the syntax table used by Fundamental mode.
This function returns the standard syntax table, which is the syntax table used in Fundamental mode.
Syntax tables are not used by the Emacs Lisp reader, which has its own built-in syntactic rules which cannot be changed. (Some Lisp systems provide ways to redefine the read syntax, but we decided to leave this feature out of Emacs Lisp for simplicity.)
The syntax class of a character describes its syntactic role. Each syntax table specifies the syntax class of each character. There is no necessary relationship between the class of a character in one syntax table and its class in any other table.
Each syntax class is designated by a mnemonic character, which serves as the name of the class when you need to specify a class. Usually, this designator character is one that is often assigned that class; however, its meaning as a designator is unvarying and independent of what syntax that character currently has. Thus, ‘\’ as a designator character always stands for escape character syntax, regardless of whether the ‘\’ character actually has that syntax in the current syntax table. See Table of Syntax Classes, for a list of syntax classes and their designator characters.
A syntax descriptor is a Lisp string that describes the syntax
class and other syntactic properties of a character. When you want to
modify the syntax of a character, that is done by calling the function
modify-syntax-entry and passing a syntax descriptor as one of
its arguments (see Syntax Table Functions).
The first character in a syntax descriptor must be a syntax class designator character. The second character, if present, specifies a matching character (e.g., in Lisp, the matching character for ‘(’ is ‘)’); a space specifies that there is no matching character. Then come characters specifying additional syntax properties (see Syntax Flags).
If no matching character or flags are needed, only one character (specifying the syntax class) is sufficient.
For example, the syntax descriptor for the character ‘*’ in C
mode is ". 23" (i.e., punctuation, matching character slot
unused, second character of a comment-starter, first character of a
comment-ender), and the entry for ‘/’ is ‘. 14’ (i.e.,
punctuation, matching character slot unused, first character of a
comment-starter, second character of a comment-ender).
Emacs also defines raw syntax descriptors, which are used to describe syntax classes at a lower level. See Syntax Table Internals.
Here is a table of syntax classes, the characters that designate them, their meanings, and examples of their use.
Characters that separate symbols and words from each other. Typically, whitespace characters have no other syntactic significance, and multiple whitespace characters are syntactically equivalent to a single one. Space, tab, and formfeed are classified as whitespace in almost all major modes.
This syntax class can be designated by either ‘ ’ or ‘-’. Both designators are equivalent.
Parts of words in human languages. These are typically used in variable and command names in programs. All upper- and lower-case letters, and the digits, are typically word constituents.
Extra characters used in variable and command names along with word constituents. Examples include the characters ‘$&*+-_<>’ in Lisp mode, which may be part of a symbol name even though they are not part of English words. In standard C, the only non-word-constituent character that is valid in symbols is underscore (‘_’).
Characters used as punctuation in a human language, or used in a programming language to separate symbols from one another. Some programming language modes, such as Emacs Lisp mode, have no characters in this class since the few characters that are not symbol or word constituents all have other uses. Other programming language modes, such as C mode, use punctuation syntax for operators.
Characters used in dissimilar pairs to surround sentences or expressions. Such a grouping is begun with an open parenthesis character and terminated with a close. Each open parenthesis character matches a particular close parenthesis character, and vice versa. Normally, Emacs indicates momentarily the matching open parenthesis when you insert a close parenthesis. See Blinking Parentheses.
In human languages, and in C code, the parenthesis pairs are ‘()’, ‘[]’, and ‘{}’. In Emacs Lisp, the delimiters for lists and vectors (‘()’ and ‘[]’) are classified as parenthesis characters.
Characters used to delimit string constants. The same string quote character appears at the beginning and the end of a string. Such quoted strings do not nest.
The parsing facilities of Emacs consider a string as a single token. The usual syntactic meanings of the characters in the string are suppressed.
The Lisp modes have two string quote characters: double-quote (‘"’) and vertical bar (‘|’). ‘|’ is not used in Emacs Lisp, but it is used in Common Lisp. C also has two string quote characters: double-quote for strings, and apostrophe (‘'’) for character constants.
Human text has no string quote characters. We do not want quotation marks to turn off the usual syntactic properties of other characters in the quotation.
Characters that start an escape sequence, such as is used in string and character constants. The character ‘\’ belongs to this class in both C and Lisp. (In C, it is used thus only inside strings, but it turns out to cause no trouble to treat it this way throughout C code.)
Characters in this class count as part of words if
words-include-escapes is non-nil. See Motion by Words.
Characters used to quote the following character so that it loses its normal syntactic meaning. This differs from an escape character in that only the character immediately following is ever affected.
Characters in this class count as part of words if
words-include-escapes is non-nil. See Motion by Words.
This class is used for backslash in TeX mode.
Similar to string quote characters, except that the syntactic properties of the characters between the delimiters are not suppressed. Only TeX mode uses a paired delimiter presently—the ‘$’ that both enters and leaves math mode.
Characters used for syntactic operators that are considered as part of an expression if they appear next to one. In Lisp modes, these characters include the apostrophe, ‘'’ (used for quoting), the comma, ‘,’ (used in macros), and ‘#’ (used in the read syntax for certain data types).
Characters used in various languages to delimit comments. Human text has no comment characters. In Lisp, the semicolon (‘;’) starts a comment and a newline or formfeed ends one.
This syntax class does not specify a particular syntax. It says to look in the parent syntax table to find the syntax of this character.
(This syntax class is also known as “comment-fence”.) Characters that start or end a special kind of comment. Any generic comment delimiter matches any generic comment delimiter, but they cannot match a comment starter or comment ender; generic comment delimiters can only match each other.
This syntax class is primarily meant for use with the
syntax-table text property (see Syntax Properties). You
can mark any range of characters as forming a comment, by giving the
first and last characters of the range syntax-table properties
identifying them as generic comment delimiters.
(This syntax class is also known as “string-fence”.) Characters that start or end a string. This class differs from the string quote class in that any generic string delimiter can match any other generic string delimiter; but they do not match ordinary string quote characters.
This syntax class is primarily meant for use with the
syntax-table text property (see Syntax Properties). You
can mark any range of characters as forming a string constant, by
giving the first and last characters of the range syntax-table
properties identifying them as generic string delimiters.
In addition to the classes, entries for characters in a syntax table can specify flags. There are eight possible flags, represented by the characters ‘1’, ‘2’, ‘3’, ‘4’, ‘b’, ‘c’, ‘n’, and ‘p’.
All the flags except ‘p’ are used to describe comment delimiters. The digit flags are used for comment delimiters made up of 2 characters. They indicate that a character can also be part of a comment sequence, in addition to the syntactic properties associated with its character class. The flags are independent of the class and each other for the sake of characters such as ‘*’ in C mode, which is a punctuation character, and the second character of a start-of-comment sequence (‘/*’), and the first character of an end-of-comment sequence (‘*/’). The flags ‘b’, ‘c’, and ‘n’ are used to qualify the corresponding comment delimiter.
Here is a table of the possible flags for a character c, and what they mean:
Emacs supports several comment styles simultaneously in any one syntax table. A comment style is a set of flags ‘b’, ‘c’, and ‘n’, so there can be up to 8 different comment styles, each one named by the set of its flags. Each comment delimiter has a style and only matches comment delimiters of the same style. Thus if a comment starts with the comment-start sequence of style “bn”, it will extend until the next matching comment-end sequence of style “bn”. When the set of flags has neither flag ‘b’ nor flag ‘c’ set, the resulting style is called the “a” style.
The appropriate comment syntax settings for C++ can be as follows:
‘124’
‘23b’
‘>’
This defines four comment-delimiting sequences:
This is a comment-start sequence for “b” style because the second character, ‘*’, has the ‘b’ flag.
This is a comment-start sequence for “a” style because the second character, ‘/’, does not have the ‘b’ flag.
This is a comment-end sequence for “b” style because the first character, ‘*’, has the ‘b’ flag.
This is a comment-end sequence for “a” style, because the newline character does not have the ‘b’ flag.
The function backward-prefix-chars moves back over these
characters, as well as over characters whose primary syntax class is
prefix (‘'’). See Motion and Syntax.
In this section we describe functions for creating, accessing and altering syntax tables.
This function creates a new syntax table. If table is
non-nil, the parent of the new syntax table is table;
otherwise, the parent is the standard syntax table.
In the new syntax table, all characters are initially given the “inherit” (‘@’) syntax class, i.e., their syntax is inherited from the parent table (see Table of Syntax Classes).
This function constructs a copy of table and returns it. If
table is omitted or nil, it returns a copy of the
standard syntax table. Otherwise, an error is signaled if table
is not a syntax table.
This function sets the syntax entry for char according to
syntax-descriptor. char must be a character, or a cons
cell of the form (min . max); in the latter case,
the function sets the syntax entries for all characters in the range
between min and max, inclusive.
The syntax is changed only for table, which defaults to the current buffer’s syntax table, and not in any other syntax table.
The argument syntax-descriptor is a syntax descriptor, i.e., a string whose first character is a syntax class designator and whose second and subsequent characters optionally specify a matching character and syntax flags. See Syntax Descriptors. An error is signaled if syntax-descriptor is not a valid syntax descriptor.
This function always returns nil. The old syntax information in
the table for this character is discarded.
Examples:
;; Put the space character in class whitespace.
(modify-syntax-entry ?\s " ")
⇒ nil
;; Make ‘$’ an open parenthesis character, ;; with ‘^’ as its matching close. (modify-syntax-entry ?$ "(^") ⇒ nil
;; Make ‘^’ a close parenthesis character, ;; with ‘$’ as its matching open. (modify-syntax-entry ?^ ")$") ⇒ nil
;; Make ‘/’ a punctuation character, ;; the first character of a start-comment sequence, ;; and the second character of an end-comment sequence. ;; This is used in C mode. (modify-syntax-entry ?/ ". 14") ⇒ nil
This function returns the syntax class of character, represented by its designator character (see Table of Syntax Classes). This returns only the class, not its matching character or syntax flags.
The following examples apply to C mode. (We use string to make
it easier to see the character returned by char-syntax.)
;; Space characters have whitespace syntax class.
(string (char-syntax ?\s))
⇒ " "
;; Forward slash characters have punctuation syntax.
;; Note that this char-syntax call does not reveal
;; that it is also part of comment-start and -end sequences.
(string (char-syntax ?/))
⇒ "."
;; Open parenthesis characters have open parenthesis syntax.
;; Note that this char-syntax call does not reveal that
;; it has a matching character, ‘)’.
(string (char-syntax ?\())
⇒ "("
This function makes table the syntax table for the current buffer. It returns table.
This function returns the current syntax table, which is the table for the current buffer.
This command displays the contents of the syntax table of buffer (by default, the current buffer) in a help buffer.
This macro executes body using table as the current syntax table. It returns the value of the last form in body, after restoring the old current syntax table.
Since each buffer has its own current syntax table, we should make that
more precise: with-syntax-table temporarily alters the current
syntax table of whichever buffer is current at the time the macro
execution starts. Other buffers are not affected.
When the syntax table is not flexible enough to specify the syntax of
a language, you can override the syntax table for specific character
occurrences in the buffer, by applying a syntax-table text
property. See Text Properties, for how to apply text properties.
The valid values of syntax-table text property are:
If the property value is a syntax table, that table is used instead of the current buffer’s syntax table to determine the syntax for the underlying text character.
(syntax-code . matching-char)A cons cell of this format is a raw syntax descriptor (see Syntax Table Internals), which directly specifies a syntax class for the underlying text character.
nilIf the property is nil, the character’s syntax is determined from
the current syntax table in the usual way.
If this is non-nil, the syntax scanning functions, like
forward-sexp, pay attention to syntax-table text
properties. Otherwise they use only the current syntax table.
This variable, if non-nil, should store a function for applying
syntax-table properties to a specified stretch of text. It is
intended to be used by major modes to install a function which applies
syntax-table properties in some mode-appropriate way.
The function is called by syntax-ppss (see Finding the Parse State for a Position),
and by Font Lock mode during syntactic fontification (see 语法字体锁定). It is called with two arguments, start and
end, which are the starting and ending positions of the text on
which it should act. It is allowed to arbitrarily move point within
the region delimited by start and end; such motions don’t
need to use save-excursion (see Excursions). It is also
allowed to call syntax-ppss on any position before end,
but if a Lisp program calls syntax-ppss on some position and
later modifies the buffer at some earlier position, then it is that
program’s responsibility to call syntax-ppss-flush-cache to
flush the now obsolete info from the cache.
Caution: When this variable is non-nil, Emacs removes
syntax-table text properties arbitrarily and relies on
syntax-propertize-function to reapply them. Thus if this
facility is used at all, the function must apply all
syntax-table text properties used by the major mode. In
particular, Modes derived from a CC Mode mode must not use this
variable, since CC Mode uses other means to apply and remove these
text properties.
This abnormal hook is run by the syntax parsing code prior to calling
syntax-propertize-function. Its role is to help locate safe
starting and ending buffer positions for passing to
syntax-propertize-function. For example, a major mode can add
a function to this hook to identify multi-line syntactic constructs,
and ensure that the boundaries do not fall in the middle of one.
Each function in this hook should accept two arguments, start
and end. It should return either a cons cell of two adjusted
buffer positions, (new-start . new-end), or
nil if no adjustment is necessary. The hook functions are run
in turn, repeatedly, until they all return nil.
This section describes functions for moving across characters that have certain syntax classes.
This function moves point forward across characters having syntax classes mentioned in syntaxes (a string of syntax class characters). It stops when it encounters the end of the buffer, or position limit (if specified), or a character it is not supposed to skip.
If syntaxes starts with ‘^’, then the function skips characters whose syntax is not in syntaxes.
The return value is the distance traveled, which is a nonnegative integer.
This function moves point backward across characters whose syntax classes are mentioned in syntaxes. It stops when it encounters the beginning of the buffer, or position limit (if specified), or a character it is not supposed to skip.
If syntaxes starts with ‘^’, then the function skips characters whose syntax is not in syntaxes.
The return value indicates the distance traveled. It is an integer that is zero or less.
This function moves point backward over any number of characters with expression prefix syntax. This includes both characters in the expression prefix syntax class, and characters with the ‘p’ flag.
This section describes functions for parsing and scanning balanced expressions. We will refer to such expressions as sexps, following the terminology of Lisp, even though these functions can act on languages other than Lisp. Basically, a sexp is either a balanced parenthetical grouping, a string, or a symbol (i.e., a sequence of characters whose syntax is either word constituent or symbol constituent). However, characters in the expression prefix syntax class (see Table of Syntax Classes) are treated as part of the sexp if they appear next to it.
The syntax table controls the interpretation of characters, so these functions can be used for Lisp expressions when in Lisp mode and for C expressions when in C mode. See Moving over Balanced Expressions, for convenient higher-level functions for moving over balanced expressions.
A character’s syntax controls how it changes the state of the parser, rather than describing the state itself. For example, a string delimiter character toggles the parser state between in-string and in-code, but the syntax of characters does not directly say whether they are inside a string. For example (note that 15 is the syntax code for generic string delimiters),
(put-text-property 1 9 'syntax-table '(15 . nil))
does not tell Emacs that the first eight chars of the current buffer are a string, but rather that they are all string delimiters. As a result, Emacs treats them as four consecutive empty string constants.
This section describes simple point-motion functions that operate based on parsing expressions.
This function scans forward count balanced parenthetical groupings from position from. It returns the position where the scan stops. If count is negative, the scan moves backwards.
If depth is nonzero, treat the starting position as being depth parentheses deep. The scanner moves forward or backward through the buffer until the depth changes to zero count times. Hence, a positive value for depth has the effect of moving out depth levels of parenthesis from the starting position, while a negative depth has the effect of moving deeper by -depth levels of parenthesis.
Scanning ignores comments if parse-sexp-ignore-comments is
non-nil.
If the scan reaches the beginning or end of the accessible part of the
buffer before it has scanned over count parenthetical groupings,
the return value is nil if the depth at that point is zero; if
the depth is non-zero, a scan-error error is signaled.
This function scans forward count sexps from position from. It returns the position where the scan stops. If count is negative, the scan moves backwards.
Scanning ignores comments if parse-sexp-ignore-comments is
non-nil.
If the scan reaches the beginning or end of (the accessible part of) the
buffer while in the middle of a parenthetical grouping, an error is
signaled. If it reaches the beginning or end between groupings but
before count is used up, nil is returned.
This function moves point forward across count complete comments
(that is, including the starting delimiter and the terminating
delimiter if any), plus any whitespace encountered on the way. It
moves backward if count is negative. If it encounters anything
other than a comment or whitespace, it stops, leaving point at the
place where it stopped. This includes (for instance) finding the end
of a comment when moving forward and expecting the beginning of one.
The function also stops immediately after moving over the specified
number of complete comments. If count comments are found as
expected, with nothing except whitespace between them, it returns
t; otherwise it returns nil.
This function cannot tell whether the comments it traverses are embedded within a string. If they look like comments, it treats them as comments.
To move forward over all comments and whitespace following point, use
(forward-comment (buffer-size)). (buffer-size) is a
good argument to use, because the number of comments in the buffer
cannot exceed that many.
For syntactic analysis, such as in indentation, often the useful thing is to compute the syntactic state corresponding to a given buffer position. This function does that conveniently.
This function returns the parser state that the parser would reach at position pos starting from the beginning of the visible portion of the buffer. See Parser State, for a description of the parser state.
The return value is the same as if you call the low-level parsing
function parse-partial-sexp to parse from the beginning of the
visible portion of the buffer to pos (see Low-Level Parsing). However, syntax-ppss uses caches to speed up the
computation. Due to this optimization, the second value (previous
complete subexpression) and sixth value (minimum parenthesis depth) in
the returned parser state are not meaningful.
This function has a side effect: it adds a buffer-local entry to
before-change-functions (see Change Hooks) for
syntax-ppss-flush-cache (see below). This entry keeps the
cache consistent as the buffer is modified. However, the cache might
not be updated if syntax-ppss is called while
before-change-functions is temporarily let-bound, or if the
buffer is modified without running the hook, such as when using
inhibit-modification-hooks. In those cases, it is necessary to
call syntax-ppss-flush-cache explicitly.
This function flushes the cache used by syntax-ppss, starting
at position beg. The remaining arguments, ignored-args,
are ignored; this function accepts them so that it can be directly
used on hooks such as before-change-functions (see Change Hooks).
A parser state is a list of (currently) eleven elements
describing the state of the syntactic parser, after it parses the text
between a specified starting point and a specified end point in the
buffer using parse-partial-sexp (see Low-Level Parsing).
Parsing functions such as syntax-ppss
(see Finding the Parse State for a Position)
also return a parser state as the value. parse-partial-sexp
can accept a parser state as an argument, for resuming parsing.
Here are the meanings of the elements of the parser state:
nil if none.
nil if none.
nil if inside a string. More precisely, this is the
character that will terminate the string, or t if a generic
string delimiter character should terminate it.
t if inside a non-nestable comment (of any comment style;
see Syntax Flags); or the comment nesting level if inside a
comment that can be nested.
t if the end point is just after a quote character.
nil if not in a comment or in a
comment of style ‘a’; 1 for a comment of style ‘b’; 2 for a
comment of style ‘c’; and syntax-table for a comment that
should be ended by a generic comment delimiter character.
nil.
nil.
Elements 1, 2, and 6 are ignored in a state which you pass as an
argument to parse-partial-sexp to continue parsing. Elements 9
and 10 are mainly used internally by the parser code.
Some additional useful information is available from a parser state using these functions:
This function extracts, from parser state state, the last position scanned in the parse which was at top level in grammatical structure. “At top level” means outside of any parentheses, comments, or strings.
The value is nil if state represents a parse which has
arrived at a top level position.
Return string if the end position of the scan returning
state is in a string, and comment if it’s in a comment.
Otherwise return nil.
The most basic way to use the expression parser is to tell it to start at a given position with a certain state, and parse up to a specified end position.
This function parses a sexp in the current buffer starting at start, not scanning past limit. It stops at position limit or when certain criteria described below are met, and sets point to the location where parsing stops. It returns a parser state describing the status of the parse at the point where it stops.
If the third argument target-depth is non-nil, parsing
stops if the depth in parentheses becomes equal to target-depth.
The depth starts at 0, or at whatever is given in state.
If the fourth argument stop-before is non-nil, parsing
stops when it comes to any character that starts a sexp. If
stop-comment is non-nil, parsing stops after the start of
an unnested comment. If stop-comment is the symbol
syntax-table, parsing stops after the start of an unnested
comment or a string, or after the end of an unnested comment or a
string, whichever comes first.
If state is nil, start is assumed to be at the top
level of parenthesis structure, such as the beginning of a function
definition. Alternatively, you might wish to resume parsing in the
middle of the structure. To do this, you must provide a state
argument that describes the initial status of parsing. The value
returned by a previous call to parse-partial-sexp will do
nicely.
If this variable is non-nil, scan-sexps treats all
non-ASCII characters as symbol constituents regardless of
what the syntax table says about them. (However, syntax-table
text properties can still override the syntax.)
If the value is non-nil, then comments are treated as
whitespace by the functions in this section and by forward-sexp,
scan-lists and scan-sexps.
The behavior of parse-partial-sexp is also affected by
parse-sexp-lookup-properties (see Syntax Properties).
If this buffer local variable is non-nil, a single character
which usually terminates a comment doesn’t do so when that character
is escaped. This is used in C and C++ Modes, where line comments
starting with ‘//’ can be continued onto the next line by
escaping the newline with ‘\’.
You can use forward-comment to move forward or backward over
one comment or several comments.
Syntax tables are implemented as char-tables (see 字符表), but most Lisp programs don’t work directly with their elements. Syntax tables do not store syntax data as syntax descriptors (see Syntax Descriptors); they use an internal format, which is documented in this section. This internal format can also be assigned as syntax properties (see Syntax Properties).
Each entry in a syntax table is a raw syntax descriptor: a
cons cell of the form (syntax-code
. matching-char). syntax-code is an integer which
encodes the syntax class and syntax flags, according to the table
below. matching-char, if non-nil, specifies a matching
character (similar to the second character in a syntax descriptor).
Use aref (see 操作数组的函数) to get the raw syntax
descriptor of a character, for example (aref (syntax-table) ch).
Here are the syntax codes corresponding to the various syntax classes:
| Code | Class | Code | Class |
| 0 | whitespace | 8 | paired delimiter |
| 1 | punctuation | 9 | escape |
| 2 | word | 10 | character quote |
| 3 | symbol | 11 | comment-start |
| 4 | open parenthesis | 12 | comment-end |
| 5 | close parenthesis | 13 | inherit |
| 6 | expression prefix | 14 | generic comment |
| 7 | string quote | 15 | generic string |
For example, in the standard syntax table, the entry for ‘(’ is
(4 . 41). 41 is the character code for ‘)’.
Syntax flags are encoded in higher order bits, starting 16 bits from the least significant bit. This table gives the power of two which corresponds to each syntax flag.
| Prefix | Flag | Prefix | Flag |
| ‘1’ | (ash 1 16) | ‘p’ | (ash 1 20) |
| ‘2’ | (ash 1 17) | ‘b’ | (ash 1 21) |
| ‘3’ | (ash 1 18) | ‘n’ | (ash 1 22) |
| ‘4’ | (ash 1 19) | ‘c’ | (ash 1 23) |
Given a syntax descriptor desc (a string), this function returns the corresponding raw syntax descriptor.
Given a raw syntax descriptor syntax (an integer), this function returns the corresponding syntax descriptor (a character).
This function returns the raw syntax descriptor for the character in
the buffer after position pos, taking account of syntax
properties as well as the syntax table. If pos is outside the
buffer’s accessible portion (see accessible portion),
the return value is nil.
This function returns the syntax code for the raw syntax descriptor syntax. More precisely, it takes the raw syntax descriptor’s syntax-code component, masks off the high 16 bits which record the syntax flags, and returns the resulting integer.
If syntax is nil, the return value is nil. This
is so that the expression
(syntax-class (syntax-after pos))
evaluates to nil if pos is outside the buffer’s
accessible portion, without throwing errors or returning an incorrect
code.
Categories provide an alternate way of classifying characters syntactically. You can define several categories as needed, then independently assign each character to one or more categories. Unlike syntax classes, categories are not mutually exclusive; it is normal for one character to belong to several categories.
Each buffer has a category table which records which categories are defined and also which characters belong to each category. Each category table defines its own categories, but normally these are initialized by copying from the standard categories table, so that the standard categories are available in all modes.
Each category has a name, which is an ASCII printing character in
the range ‘ ’ to ‘~’. You specify the name of a category
when you define it with define-category.
The category table is actually a char-table (see 字符表).
The element of the category table at index c is a category
set—a bool-vector—that indicates which categories character c
belongs to. In this category set, if the element at index cat is
t, that means category cat is a member of the set, and that
character c belongs to category cat.
For the next three functions, the optional argument table defaults to the current buffer’s category table.
This function defines a new category, with name char and documentation docstring, for the category table table.
Here’s an example of defining a new category for characters that have strong right-to-left directionality (see Bidirectional Display) and using it in a special category table. To obtain the information about the directionality of characters, the example code uses the ‘bidi-class’ Unicode property (see bidi-class).
(defvar special-category-table-for-bidi
;; Make an empty category-table.
(let ((category-table (make-category-table))
;; Create a char-table which gives the 'bidi-class' Unicode
;; property for each character.
(uniprop-table
(unicode-property-table-internal 'bidi-class)))
(define-category ?R "Characters of bidi-class R, AL, or RLO"
category-table)
;; Modify the category entry of each character whose
;; 'bidi-class' Unicode property is R, AL, or RLO --
;; these have a right-to-left directionality.
(map-char-table
(lambda (key val)
(if (memq val '(R AL RLO))
(modify-category-entry key ?R category-table)))
uniprop-table)
category-table))
This function returns the documentation string of category category in category table table.
(category-docstring ?a)
⇒ "ASCII"
(category-docstring ?l)
⇒ "Latin"
This function returns a category name (a character) which is not
currently defined in table. If all possible categories are in use
in table, it returns nil.
This function returns the current buffer’s category table.
This function returns t if object is a category table,
otherwise nil.
This function returns the standard category table.
This function constructs a copy of table and returns it. If
table is not supplied (or is nil), it returns a copy of the
standard category table. Otherwise, an error is signaled if table
is not a category table.
This function makes table the category table for the current buffer. It returns table.
This creates and returns an empty category table. In an empty category table, no categories have been allocated, and no characters belong to any categories.
This function returns a new category set—a bool-vector—whose initial
contents are the categories listed in the string categories. The
elements of categories should be category names; the new category
set has t for each of those categories, and nil for all
other categories.
(make-category-set "al")
⇒ #&128"\0\0\0\0\0\0\0\0\0\0\0\0\2\20\0\0"
This function returns the category set for character char in the
current buffer’s category table. This is the bool-vector which
records which categories the character char belongs to. The
function char-category-set does not allocate storage, because
it returns the same bool-vector that exists in the category table.
(char-category-set ?a)
⇒ #&128"\0\0\0\0\0\0\0\0\0\0\0\0\2\20\0\0"
This function converts the category set category-set into a string containing the characters that designate the categories that are members of the set.
(category-set-mnemonics (char-category-set ?a))
⇒ "al"
This function modifies the category set of char in category
table table (which defaults to the current buffer’s category
table). char can be a character, or a cons cell of the form
(min . max); in the latter case, the function
modifies the category sets of all characters in the range between
min and max, inclusive.
Normally, it modifies a category set by adding category to it.
But if reset is non-nil, then it deletes category
instead.
This function describes the category specifications in the current
category table. It inserts the descriptions in a buffer, and then
displays that buffer. If buffer-or-name is non-nil, it
describes the category table of that buffer instead.
Emacs Lisp provides several tools for parsing and matching text, from regular expressions (see Regular Expressions) to full left-to-right (a.k.a. LL) grammar parsers (see Bovine parser development). Parsing Expression Grammars (PEG) are another approach to text parsing that offer more structure and composability than regular expressions, but less complexity than context-free grammars.
A Parsing Expression Grammar (PEG) describes a formal language
in terms of a set of rules for recognizing strings in the language. In
Emacs, a PEG parser is defined as a list of named rules, each
of which matches text patterns and/or contains references to other
rules. Parsing is initiated with the function peg-run or the
macro peg-parse (see below), and parses text after point in the
current buffer, using a given set of rules.
Each rule in a PEG is referred to as a parsing expression (PEX), and can be specified a literal string, a regexp-like character range or set, a peg-specific construct resembling an Emacs Lisp function call, a reference to another rule, or a combination of any of these. A grammar is expressed as a tree of rules in which one rule is typically treated as a “root” or “entry-point” rule. For instance:
((number sign digit (* digit)) (sign (or "+" "-" "")) (digit [0-9]))
Once defined, grammars can be used to parse text after point in the
current buffer, in a number of ways. The peg-parse macro is the
simplest:
Match pexs at point.
(peg-parse (number sign digit (* digit)) (sign (or "+" "-" "")) (digit [0-9]))
While this macro is simple it is also inflexible, as the rules must be written directly into the source code. More flexibility can be gained by using a combination of other functions and macros.
Execute body with rules, a list of PEXs, in
effect. Within BODY, parsing is initiated with a call to
peg-run.
This function accepts a single peg-matcher, which is the result of
calling peg (see below) on a named rule, usually the entry-point
of a larger grammar.
At the end of parsing, one of failure-function or success-function is called, depending on whether the parsing succeeded or not. If success-function is provided, it should be a function that receives as its only argument an anonymous function that runs all the actions collected on the stack during parsing. By default this anonymous function is simply executed. If parsing fails, a function provided as failure-function will be called with a list of PEG expressions that failed during parsing. By default this list is discarded.
The peg-matcher passed to peg-run is produced by a call to
peg:
Convert pexs into a single peg-matcher suitable for passing to
peg-run.
The peg-parse example above expands to a set of calls to these
functions, and could be written in full as:
(with-peg-rules
((number sign digit (* digit))
(sign (or "+" "-" ""))
(digit [0-9]))
(peg-run (peg number)))
This approach allows more explicit control over the “entry-point” of parsing, and allows the combination of rules from different sources.
Individual rules can also be defined using a more defun-like
syntax, using the macro define-peg-rule:
Define name as a PEG rule that accepts args and matches pexs at point.
For instance:
(define-peg-rule digit () [0-9])
Arguments can be supplied to rules by the funcall PEG rule
(see PEX Definitions).
Another possibility is to define a named set of rules with
define-peg-ruleset:
Define name as an identifier for rules.
(define-peg-ruleset number-grammar ;; `digit' here references the definition above. (number () sign digit (* digit)) (sign () (or "+" "-" "")))
Rules and rulesets defined this way can be referred to by name in
later calls to peg-run or with-peg-rules:
(with-peg-rules number-grammar (peg-run (peg number)))
By default, calls to peg-run or peg-parse produce no
output: parsing simply moves point. In order to return or otherwise
act upon parsed strings, rules can include actions, see
Parsing Actions.
Parsing expressions can be defined using the following syntax:
(and e1 e2…)A sequence of PEXs that must all be matched. The and
form is optional and implicit.
(or e1 e2…)Prioritized choices, meaning that, as in Elisp, the choices are tried in order, and the first successful match is used. Note that this is distinct from context-free grammars, in which selection between multiple matches is indeterminate.
(any)Matches any single character, as the regexp “.”.
stringA literal string.
(char c)A single character c, as an Elisp character literal.
(* e)Zero or more instances of expression e, as the regexp ‘*’. Matching is always “greedy”.
(+ e)One or more instances of expression e, as the regexp ‘+’. Matching is always “greedy”.
(opt e)Zero or one instance of expression e, as the regexp ‘?’.
symbolA symbol representing a previously-defined PEG rule.
(range ch1 ch2)The character range between ch1 and ch2, as the regexp ‘[ch1-ch2]’.
[ch1-ch2 "+*" ?x]A character set, which can include ranges, character literals, or strings of characters.
[ascii cntrl]A list of named character classes.
(syntax-class name)A single syntax class.
(funcall e args…)Call PEX e (previously defined with
define-peg-rule) with arguments args.
(null)The empty string.
The following expressions are used as anchors or tests – they do not move point, but return a boolean value which can be used to constrain matches as a way of controlling the parsing process (see Writing PEG Rules).
(bob)Beginning of buffer.
(eob)End of buffer.
(bol)Beginning of line.
(eol)End of line.
(bow)Beginning of word.
(eow)End of word.
(bos)Beginning of symbol.
(eos)End of symbol.
(if e)Returns non-nil if parsing PEX e from point
succeeds (point is not moved).
(not e)Returns non-nil if parsing PEX e from point fails
(point is not moved).
(guard exp)Treats the value of the Lisp expression exp as a boolean.
Character-class matching can refer to the classes named in
peg-char-classes, equivalent to character classes in regular
expressions (see Character Classes)
By default the process of parsing simply moves point in the current
buffer, ultimately returning t if the parsing succeeds, and
nil if it doesn’t. It’s also possible to define parsing
actions that can run arbitrary Elisp at certain points in the parsed
text. These actions can optionally affect something called the
parsing stack, which is a list of values returned by the parsing
process. These actions only run (and only return values) if the parsing
process ultimately succeeds; if it fails the action code is not run at
all.
Actions can be added anywhere in the definition of a rule. They are distinguished from parsing expressions by an initial backquote (‘`’), followed by a parenthetical form that must contain a pair of hyphens (‘--’) somewhere within it. Symbols to the left of the hyphens are bound to values popped from the stack (they are somewhat analogous to the argument list of a lambda form). Values produced by code to the right of the hyphens are pushed onto the stack (analogous to the return value of the lambda). For instance, the previous grammar can be augmented with actions to return the parsed number as an actual integer:
(with-peg-rules ((number sign digit (* digit
`(a b -- (+ (* a 10) b)))
`(sign val -- (* sign val)))
(sign (or (and "+" `(-- 1))
(and "-" `(-- -1))
(and "" `(-- 1))))
(digit [0-9] `(-- (- (char-before) ?0))))
(peg-run (peg number)))
There must be values on the stack before they can be popped and
returned – if there aren’t enough stack values to bind to an action’s
left-hand terms, they will be bound to nil. An action with
only right-hand terms will push values to the stack; an action with
only left-hand terms will consume (and discard) values from the stack.
At the end of parsing, stack values are returned as a flat list.
To return the string matched by a PEX (instead of simply moving point over it), a grammar can use a rule like this:
(one-word `(-- (point)) (+ [word]) `(start -- (buffer-substring start (point))))
The first action above pushes the initial value of point to the stack.
The intervening PEX moves point over the next word. The
second action pops the previous value from the stack (binding it to the
variable start), then uses that value to extract a substring from
the buffer and push it to the stack. This pattern is so common that
PEG provides a shorthand function that does exactly the above,
along with a few other shorthands for common scenarios:
(substring e) ¶Match PEX e and push the matched string onto the stack.
(region e) ¶Match e and push the start and end positions of the matched region onto the stack.
(replace e replacement) ¶Match e and replaced the matched region with the string replacement.
(list e) ¶Match e, collect all values produced by e (and its sub-expressions) into a list, and push that list onto the stack. Stack values are typically returned as a flat list; this is a way of “grouping” values together.
Something to be aware of when writing PEG rules is that they are greedy. Rules which can consume a variable amount of text will always consume the maximum amount possible, even if that causes a rule that might otherwise have matched to fail later on – there is no backtracking. For instance, this rule will never succeed:
(forest (+ "tree" (* [blank])) "tree" (eol))
The PEX (+ "tree" (* [blank])) will consume all
the repetitions of the word ‘tree’, leaving none to match the final
‘tree’.
In these situations, the desired result can be obtained by using
predicates and guards – namely the not, if and
guard expressions – to constrain behavior. For instance:
(forest (+ "tree" (* [blank])) (not (eol)) "tree" (eol))
The if and not operators accept a parsing expression and
interpret it as a boolean, without moving point. The contents of a
guard operator are evaluated as regular Lisp (not a
PEX) and should return a boolean value. A nil value
causes the match to fail.
Another potentially unexpected behavior is that parsing will move point as far as possible, even if the parsing ultimately fails. This rule:
(end-game "game" (eob))
when run in a buffer containing the text “game over” after point,
will move point to just after “game” then halt parsing, returning
nil. Successful parsing will always return t, or the
contexts of the parsing stack.
Emacs provides various ways to parse program source text and produce a syntax tree. In a syntax tree, text is no longer considered a one-dimensional stream of characters, but a structured tree of nodes, where each node represents a piece of text. Thus, a syntax tree can enable interesting features like precise fontification, indentation, navigation, structured editing, etc.
Emacs has a simple facility for parsing balanced expressions (see Parsing Expressions). There is also the SMIE library for generic navigation and indentation (see 简易缩进引擎(SMIE)).
In addition to those, Emacs also provides integration with the tree-sitter library if support for it was compiled in. The tree-sitter library implements an incremental parser and has support for a wide range of programming languages.
This function returns non-nil if tree-sitter features are
available for the current Emacs session.
To be able to parse the program source using the tree-sitter library and access the syntax tree of the program, a Lisp program needs to load a language grammar library, and create a parser for that language and the current buffer. After that, the Lisp program can query the parser about specific nodes of the syntax tree. Then, it can access various kinds of information about each node, and search for nodes using a powerful pattern-matching syntax. This chapter explains how to do all this, and also how a Lisp program can work with source files that mix multiple programming languages.
Tree-sitter relies on language grammar to parse text in that
language. In Emacs, a language grammar is represented by a symbol.
For example, the C language grammar is represented as the symbol
c, and c can be passed to tree-sitter functions as the
language argument.
Tree-sitter language grammars are distributed as dynamic libraries. In order to use a language grammar in Emacs, you need to make sure that the dynamic library is installed on the system. Emacs looks for language grammars in several places, in the following order:
treesit-extra-load-path;
user-emacs-directory (see The Init File);
In each of these directories, Emacs looks for a file with file-name
extensions specified by the variable dynamic-library-suffixes.
If Emacs cannot find the library or has problems loading it, Emacs
signals the treesit-load-language-error error. The data of
that signal could be one of the following:
(not-found error-msg …)This means that Emacs could not find the language grammar library.
(symbol-error error-msg)This means that Emacs could not find in the library the expected function that every language grammar library should export.
(version-mismatch error-msg)This means that the version of the language grammar library is incompatible with that of the tree-sitter library.
In all of these cases, error-msg might provide additional details about the failure.
This function returns non-nil if the language grammar for
language exists and can be loaded.
If detail is non-nil, return (t . nil) when
language is available, and (nil . data) when it’s
unavailable. data is the signal data of
treesit-load-language-error.
By convention, the file name of the dynamic library for language is
libtree-sitter-language.ext, where ext is the
system-specific extension for dynamic libraries. Also by convention,
the function provided by that library is named
tree_sitter_language. If a language grammar library
doesn’t follow this convention, you should add an entry
(language library-base-name function-name)
to the list in the variable treesit-load-name-override-list, where
library-base-name is the basename of the dynamic library’s file name
(usually, libtree-sitter-language), and
function-name is the function provided by the library
(usually, tree_sitter_language). For example,
(cool-lang "libtree-sitter-coool" "tree_sitter_cooool")
for a language that considers itself too “cool” to abide by conventions.
This function returns the version of the language grammar
Application Binary Interface (ABI) supported by the
tree-sitter library. By default, it returns the latest ABI version
supported by the library, but if min-compatible is
non-nil, it returns the oldest ABI version which the library
still can support. Language grammar libraries must be built for
ABI versions between the oldest and the latest versions supported by
the tree-sitter library, otherwise the library will be unable to load
them.
This function returns the ABI version of the language
grammar library loaded by Emacs for language. If language
is unavailable, this function returns nil.
A syntax tree is what a parser generates. In a syntax tree, each node represents a piece of text, and is connected to each other by a parent-child relationship. For example, if the source text is
1 + 2
its syntax tree could be
+--------------+
| root "1 + 2" |
+--------------+
|
+--------------------------------+
| expression "1 + 2" |
+--------------------------------+
| | |
+------------+ +--------------+ +------------+
| number "1" | | operator "+" | | number "2" |
+------------+ +--------------+ +------------+
We can also represent it as an s-expression:
(root (expression (number) (operator) (number)))
Names like root, expression, number, and
operator specify the type of the nodes. However, not all
nodes in a syntax tree have a type. Nodes that don’t have a type are
known as anonymous nodes, and nodes with a type are named
nodes. Anonymous nodes are tokens with fixed spellings, including
punctuation characters like bracket ‘]’, and keywords like
return.
To make the syntax tree easier to analyze, many language grammar
assign field names to child nodes. For example, a
function_definition node could have a declarator and a
body:
(function_definition declarator: (declaration) body: (compound_statement))
To aid in understanding the syntax of a language and in debugging Lisp programs that use the syntax tree, Emacs provides an “explore” mode, which displays the syntax tree of the source in the current buffer in real time. Emacs also comes with an “inspect mode”, which displays information of the nodes at point in the mode-line.
This mode pops up a window displaying the syntax tree of the source in the current buffer. Selecting text in the source buffer highlights the corresponding nodes in the syntax tree display. Clicking on nodes in the syntax tree highlights the corresponding text in the source buffer.
This minor mode displays on the mode-line the node that starts at point. For example, the mode-line can display
parent field: (node (child (...)))
where node, child, etc., are nodes which begin at point. parent is the parent of node. node is displayed in a bold typeface. field-names are field names of node and of child, etc.
If no node starts at point, i.e., point is in the middle of a node, then the mode line displays the earliest node that spans point, and its immediate parent.
This minor mode doesn’t create parsers on its own. It uses the first
parser in (treesit-parser-list) (see Using Tree-sitter Parser).
Authors of language grammars define the grammar of a programming language, which determines how a parser constructs a concrete syntax tree out of the program text. In order to use the syntax tree effectively, you need to consult the grammar file.
The grammar file is usually grammar.js in a language grammar’s project repository. The link to a language grammar’s home page can be found on tree-sitter’s homepage.
The grammar definition is written in JavaScript. For example, the
rule matching a function_definition node may look like
function_definition: $ => seq(
$.declaration_specifiers,
field('declarator', $.declaration),
field('body', $.compound_statement)
)
The rules are represented by functions that take a single argument
$, representing the whole grammar. The function itself is
constructed by other functions: the seq function puts together
a sequence of children; the field function annotates a child
with a field name. If we write the above definition in the so-called
Backus-Naur Form (BNF) syntax, it would look like
function_definition := <declaration_specifiers> <declaration> <compound_statement>
and the node returned by the parser would look like
(function_definition (declaration_specifier) declarator: (declaration) body: (compound_statement))
Below is a list of functions that one can see in a grammar definition. Each function takes other rules as arguments and returns a new rule.
seq(rule1, rule2, …)matches each rule one after another.
choice(rule1, rule2, …)matches one of the rules in its arguments.
repeat(rule)matches rule zero or more times. This is like the ‘*’ operator in regular expressions.
repeat1(rule)matches rule one or more times. This is like the ‘+’ operator in regular expressions.
optional(rule)matches rule zero or one times. This is like the ‘?’ operator in regular expressions.
field(name, rule)assigns field name name to the child node matched by rule.
alias(rule, alias)makes nodes matched by rule appear as alias in the syntax tree generated by the parser. For example,
alias(preprocessor_call_exp, call_expression)
makes any node matched by preprocessor_call_exp appear as
call_expression.
Below are grammar functions of lesser importance for reading a language grammar.
token(rule)marks rule to produce a single leaf node. That is, instead of generating a parent node with individual child nodes under it, everything is combined into a single leaf node. See Retrieving Nodes.
token.immediate(rule)Normally, grammar rules ignore preceding whitespace; this changes rule to match only when there is no preceding whitespace.
prec(n, rule)gives rule the level-n precedence.
prec.left([n,] rule)marks rule as left-associative, optionally with level n.
prec.right([n,] rule)marks rule as right-associative, optionally with level n.
prec.dynamic(n, rule)this is like prec, but the precedence is applied at runtime
instead.
The documentation of the tree-sitter project has more about writing a grammar. Read especially “The Grammar DSL” section.
This section describes how to create and configure a tree-sitter parser. In Emacs, each tree-sitter parser is associated with a buffer. As the user edits the buffer, the associated parser and syntax tree are automatically kept up-to-date.
This variable contains the maximum size of buffers in which tree-sitter can be activated. Major modes should check this value when deciding whether to enable tree-sitter features.
Create a parser for the specified buffer and language
(see Tree-sitter Language Grammar), with tag. If buffer is
omitted or nil, it stands for the current buffer.
By default, this function reuses a parser if one already exists for
language with tag in buffer, but if no-reuse
is non-nil, this function always creates a new parser.
tag can be any symbol except t, and defaults to
nil. Different parsers can have the same tag.
If that buffer is an indirect buffer, its base buffer is used instead. That is, indirect buffers use their base buffer’s parsers. If the base buffer is narrowed, an indirect buffer might not be able to retrieve information of the portion of the buffer text that is invisible in the base buffer. Lisp programs should widen as necessary should they want to use a parser in an indirect buffer.
Given a parser, we can query information about it.
This function returns the buffer associated with parser.
This function returns the language used by parser.
This function checks if object is a tree-sitter parser, and
returns non-nil if it is, and nil otherwise.
There is no need to explicitly parse a buffer, because parsing is done automatically and lazily. A parser only parses when a Lisp program queries for a node in its syntax tree. Therefore, when a parser is first created, it doesn’t parse the buffer; it waits until the Lisp program queries for a node for the first time. Similarly, when some change is made in the buffer, a parser doesn’t re-parse immediately.
When a parser does parse, it checks for the size of the buffer.
Tree-sitter can only handle buffers no larger than about 4GB. If the
size exceeds that, Emacs signals the treesit-buffer-too-large
error with signal data being the buffer size.
Once a parser is created, Emacs automatically adds it to the internal parser list. Every time a change is made to the buffer, Emacs updates parsers in this list so they can update their syntax tree incrementally.
This function returns the parser list of buffer, filtered by
language and tag. If buffer is nil or
omitted, it defaults to the current buffer. If that buffer is an
indirect buffer, its base buffer is used instead. That is, indirect
buffers use their base buffer’s parsers.
If language is non-nil, only include parsers for that
language, and only include parsers with tag. tag defaults
to nil. If tag is t, include parsers in the
returned list regardless of their tag.
This function deletes parser.
Normally, a parser “sees” the whole buffer, but when the buffer is narrowed (see Narrowing), the parser will only see the accessible portion of the buffer. As far as the parser can tell, the hidden region was deleted. When the buffer is later widened, the parser thinks text is inserted at the beginning and at the end. Although parsers respect narrowing, modes should not use narrowing as a means to handle a multi-language buffer; instead, set the ranges in which the parser should operate. See Parsing Text in Multiple Languages.
Because a parser parses lazily, when the user or a Lisp program narrows the buffer, the parser is not affected immediately; as long as the mode doesn’t query for a node while the buffer is narrowed, the parser is oblivious of the narrowing.
Besides creating a parser for a buffer, a Lisp program can also parse a string. Unlike a buffer, parsing a string is a one-off operation, and there is no way to update the result.
This function parses string using language, and returns the root node of the generated syntax tree.
A Lisp program might want to be notified of text affected by incremental parsing. For example, inserting a comment-closing token converts text before that token into a comment. Even though the text is not directly edited, it is deemed to be “changed” nevertheless.
Emacs lets a Lisp program register callback functions (a.k.a.
notifiers) for these kinds of changes. A notifier function
takes two arguments: ranges and parser. ranges is a
list of cons cells of the form (start . end),
where start and end mark the start and the end positions
of a range. parser is the parser issuing the notification.
Every time a parser reparses a buffer, it compares the old and new parse-tree, computes the ranges in which nodes have changed, and passes the ranges to notifier functions. Note that the initial parse is also considered a “change”, so notifier functions are called on the initial parse, with range being the whole buffer.
This function adds function to parser’s list of after-change notifier functions. function must be a function symbol, not a lambda function (see 匿名函数).
This function removes function from the list of parser’s after-change notifier functions. function must be a function symbol, rather than a lambda function.
This function returns the list of parser’s notifier functions.
Here are some terms and conventions we use when documenting tree-sitter functions.
A node in a syntax tree spans some portion of the program text in the buffer. We say that a node is “smaller” or “larger” than another if it spans, respectively, a smaller or larger portion of buffer text than the other node. Since nodes that are deeper (“lower”) in the tree are children of the nodes that are “higher” in the tree, it follows that a lower node will always be smaller than a node that is higher in the node hierarchy. A node that is higher up in the syntax tree contains one or more smaller nodes as its children, and therefore spans a larger portion of buffer text.
When a function cannot find a node, it returns nil. For
convenience, all functions that take a node as argument and return
a node, also accept the node argument of nil and in that case
just return nil.
Nodes are not automatically updated when the associated buffer is
modified, and there is no way to update a node once it is retrieved.
Using an outdated node signals the treesit-node-outdated error.
This function returns a leaf node at buffer position pos. A leaf node is a node that doesn’t have any child nodes.
This function tries to return a node whose span covers pos: the node’s beginning position is less than or equal to pos, and the node’s end position is greater than or equal to pos.
If no leaf node’s span covers pos (e.g., pos is in the whitespace between two leaf nodes), this function returns the first leaf node after pos.
Finally, if there is no leaf node after pos, return the first leaf node before pos.
If parser-or-lang is a parser object, this function uses that
parser; if parser-or-lang is a language, this function uses the
first parser for that language in the current buffer, or creates one
if none exists; if parser-or-lang is nil, this function
tries to guess the language at pos by calling
treesit-language-at (see Parsing Text in Multiple Languages).
If this function cannot find a suitable node to return, it returns
nil.
If named is non-nil, this function looks only for named
nodes (see named node).
Example:
;; Find the node at point in a C parser's syntax tree. (treesit-node-at (point) 'c) ⇒ #<treesit-node (primitive_type) in 23-27>
This function returns the smallest node that covers the region of buffer text between beg and end. In other words, the start of the node is before or at beg, and the end of the node is at or after end.
Beware: calling this function on an empty line that is not
inside any top-level construct (function definition, etc.) most
probably will give you the root node, because the root node is the
smallest node that covers that empty line. Most of the time, you want
to use treesit-node-at instead.
If parser-or-lang is a parser object, this function uses that
parser; if parser-or-lang is a language, this function uses the
first parser for that language in the current buffer, or creates one
if none exists; if parser-or-lang is nil, this function
tries to guess the language at beg by calling
treesit-language-at.
If named is non-nil, this function looks for a named node
only (see named node).
This function returns the root node of the syntax tree generated by parser.
This function finds the first parser for language in the current
buffer, or creates one if none exists, and returns the root node
generated by that parser. If language is omitted, it uses the
first parser in the parser list. If it cannot find an appropriate
parser, it returns nil.
Given a node, a Lisp program can retrieve other nodes starting from it, or query for information about this node.
This function returns the immediate parent of node.
If node is more than 1000 levels deep in a parse tree, the
return value is undefined. Currently it returns nil, but that
could change in the future.
This function returns the n’th child of node. If
named is non-nil, it counts only named nodes
(see named node).
For example, in a node that represents a string "text", there
are three children nodes: the opening quote ", the string text
text, and the closing quote ". Among these nodes, the
first child is the opening quote ", and the first named child
is the string text.
This function returns nil if there is no n’th child.
n could be negative, e.g., −1 represents the last child.
This function returns all of node’s children as a list. If
named is non-nil, it retrieves only named nodes.
This function finds the next sibling of node. If named is
non-nil, it finds the next named sibling.
This function finds the previous sibling of node. If
named is non-nil, it finds the previous named sibling.
To make the syntax tree easier to analyze, many language grammars
assign field names to child nodes (see field name). For example, a function_definition node
could have a declarator child and a body child.
This function finds the child of node whose field name is field-name, a string.
;; Get the child that has "body" as its field name. (treesit-node-child-by-field-name node "body") ⇒ #<treesit-node (compound_statement) in 45-89>
This function finds the first child of node that extends beyond
buffer position pos. “Extends beyond” means the end of the
child node is greater or equal to pos. This function only looks
for immediate children of node, and doesn’t look in its
grandchildren. If named is non-nil, it looks for the
first named child (see named node).
This function finds the smallest descendant node of node
that spans the region of text between positions beg and
end. It is similar to treesit-node-at. If named
is non-nil, it looks for the smallest named child.
This function traverses the subtree of node (including node
itself), looking for a node for which predicate returns
non-nil. predicate is a regexp that is matched against
each node’s type, or a predicate function that takes a node and returns
non-nil if the node matches. predicate can also be a thing
symbol or thing definition (see User-defined “Things” and Navigation). Using an
undefined thing doesn’t raise an error, the function simply returns
nil.
This function returns the first node that matches, or nil if none
matches predicate.
By default, this function only traverses named nodes, but if all
is non-nil, it traverses all the nodes. If backward is
non-nil, it traverses backwards (i.e., it visits the last child
first when traversing down the tree). If depth is
non-nil, it must be a number that limits the tree traversal to
that many levels down the tree. If depth is nil, it
defaults to 1000.
Like treesit-search-subtree, this function also traverses the
parse tree and matches each node with predicate (except for
start), where predicate can be a regexp or a predicate
function. predicate can also be a thing symbol or thing
definition (see User-defined “Things” and Navigation). Using an undefined thing
doesn’t raise an error, the function simply returns nil.
For a tree like the one below where start is marked ‘S’, this function traverses as numbered from 1 to 12:
12
|
S--------3----------11
| | |
o--o-+--o 1--+--2 6--+-----10
| | | |
o o +-+-+ +--+--+
| | | | |
4 5 7 8 9
Note that this function doesn’t traverse the subtree of start, and it always traverses leaf nodes first, before moving upwards.
Like treesit-search-subtree, this function only searches for
named nodes by default, but if all is non-nil, it
searches for all nodes. If backward is non-nil, it
searches backwards.
While treesit-search-subtree traverses the subtree of a node,
this function starts with node start and traverses every node
that comes after it in the buffer position order, i.e., nodes with
start positions greater than the end position of start.
In the tree shown above, treesit-search-subtree traverses node
‘S’ (start) and nodes marked with o, whereas this
function traverses the nodes marked with numbers. This function is
useful for answering questions like “what is the first node after
start in the buffer that satisfies some condition?”
This function moves point to the start or end of the next node after
node in the buffer that matches predicate. If start
is non-nil, stop at the beginning rather than the end of a node.
This function guarantees that the matched node it returns makes progress in terms of buffer position: the start/end position of the returned node is always greater than that of node.
Arguments predicate, backward, and all are the same
as in treesit-search-forward.
This function creates a sparse tree from root’s subtree.
It takes the subtree under root, and combs it so only the nodes
that match predicate are left. Like previous functions, the
predicate can be a regexp string that matches against each node’s
type, or a function that takes a node and returns non-nil if it
matches. predicate can also be a thing symbol or thing definition
(see User-defined “Things” and Navigation). Using an undefined thing doesn’t raise
an error, the function simply returns nil.
For example, given the subtree on the left that consists of both numbers and letters, if predicate is “letter only”, the returned tree is the one on the right.
a a a
| | |
+---+---+ +---+---+ +---+---+
| | | | | | | | |
b 1 2 b | | b c d
| | => | | => |
c +--+ c + e
| | | | |
+--+ d 4 +--+ d
| | |
e 5 e
If process-fn is non-nil, instead of returning the
matched nodes, this function passes each node to process-fn and
uses the returned value instead. If non-nil, depth
limits the number of levels to go down from root. If
depth is nil, it defaults to 1000.
Each node in the returned tree looks like
(tree-sitter-node . (child …)). The
tree-sitter-node of the root of this tree will be nil if
root doesn’t match predicate. If no node matches
predicate, the function returns nil.
This is a convenience function that chains together multiple node accessor functions together. For example, to get node’s parent’s next sibling’s second child’s text:
(treesit-node-get node
'((parent 1)
(sibling 1 nil)
(child 1 nil)
(text nil)))
instruction is a list of INSTRUCTIONs of the form
(fn arg...). The following fn’s are
supported:
(child idx named)Get the idx’th child.
(parent n)Go to parent n times.
(field-name)Get the field name of the current node.
(type)Get the type of the current node.
(text no-property)Get the text of the current node.
(children named)Get a list of children.
(sibling step named)Get the nth prev/next sibling, negative step means prev sibling, positive means next sibling.
Note that arguments like named and no-property can’t be omitted, unlike in their original functions.
This function finds immediate children of node that satisfy predicate.
The predicate function takes a node as argument and should
return non-nil to indicate that the node should be kept. If
named is non-nil, this function only examines named
nodes.
This function repeatedly finds the parents of node, and returns
the parent that satisfies predicate. predicate can be
either a function that takes a node as argument and returns t
or nil, or a regexp matching node type names, or other valid
predicates described in treesit-thing-settings. If no parent
satisfies predicates, this function returns nil.
Normally this function only looks at the parents of node but not
node itself. But if include-node is non-nil, this
function returns node if node satisfies predicate.
This function goes up the tree starting from node, and keeps doing so as long as the nodes satisfy predicate, a function that takes a node as argument. That is, this function returns the highest parent of node that still satisfies predicate. Note that if node satisfies predicate but its immediate parent doesn’t, node itself is returned.
This function returns the highest parent of node that has the
same type as node. If no such parent exists, it returns
nil. Therefore this function is also useful for testing
whether node is top-level.
If predicate is nil, this function uses node’s type
to find the parent. If predicate is non-nil, this
function searches the parent that satisfies predicate. If
include-node is non-nil, this function returns node
if node satisfies predicate.
Every node is associated with a parser, and that parser is associated with a buffer. The following functions retrieve them.
This function returns node’s associated parser.
This function returns node’s parser’s associated buffer.
This function returns node’s parser’s associated language.
Each node represents a portion of text in the buffer. Functions below find relevant information about that text.
Return the start position of node.
Return the end position of node.
Return the buffer text that node represents, as a string. (If node is retrieved from parsing a string, it will be the text from that string.)
Here are some predicates on tree-sitter nodes:
Checks if object is a tree-sitter syntax node.
Checks if node1 and node2 refer to the same node in a
tree-sitter syntax tree. This function uses the same equivalence
metric as equal. You can also compare nodes using equal
(see 相等性谓词).
In general, nodes in a concrete syntax tree fall into two categories: named nodes and anonymous nodes. Whether a node is named or anonymous is determined by the language grammar (see named node).
Apart from being named or anonymous, a node can have other properties. A node can be “missing”: such nodes are inserted by the parser in order to recover from certain kinds of syntax errors, i.e., something should probably be there according to the grammar, but is not there. This can happen during editing of the program source, when the source is not yet in its final form.
A node can be “extra”: such nodes represent things like comments, which can appear anywhere in the text.
A node can be “outdated”, if its parser has reparsed at least once after the node was created.
A node “has error” if the text it spans contains a syntax error. It can be that the node itself has an error, or one of its descendants has an error.
A node is considered live if its parser is not deleted, and the buffer to which it belongs is a live buffer (see Killing Buffers).
This function returns non-nil if node has the specified
property. property can be named, missing,
extra, outdated, has-error, or live.
Named nodes have “types” (see node type).
For example, a named node can be a string_literal node, where
string_literal is its type. The type of an anonymous node is
just the text that the node represents; e.g., the type of a ‘,’
node is just ‘,’.
This function returns node’s type as a string.
This function returns the index of node as a child node of its
parent. If named is non-nil, it only counts named nodes
(see named node).
A child of a parent node could have a field name (see field name). This function returns the field name of node as a child of its parent.
This function returns the field name of the n’th child of
node. It returns nil if there is no n’th child, or
the n’th child doesn’t have a field name.
Note that n counts both named and anonymous children, and n can be negative, e.g., −1 represents the last child.
This function returns the number of children of node. If
named is non-nil, it only counts named children
(see named node).
This function returns non-nil if smaller is enclosed in
larger. smaller and larger can be either a cons
(beg . end) or a node.
Return non-nil if larger’s start <= smaller’s start
and larger’s end <= smaller’s end.
If strict is t, compare with < rather than <=.
If strict is partial, consider larger encloses
smaller when at least one side is strictly enclosing.
Tree-sitter lets Lisp programs match patterns using a small declarative language. This pattern matching consists of two steps: first tree-sitter matches a pattern against nodes in the syntax tree, then it captures specific nodes that matched the pattern and returns the captured nodes.
We describe first how to write the most basic query pattern and how to capture nodes in a pattern, then the pattern-matching function, and finally the more advanced pattern syntax.
A query consists of multiple patterns. Each pattern is an
s-expression that matches a certain node in the syntax node. A
pattern has the form (type (child…)).
For example, a pattern that matches a binary_expression node that
contains number_literal child nodes would look like
(binary_expression (number_literal))
To capture a node using the query pattern above, append
@capture-name after the node pattern you want to
capture. For example,
(binary_expression (number_literal) @number-in-exp)
captures number_literal nodes that are inside a
binary_expression node with the capture name
number-in-exp.
We can capture the binary_expression node as well, with, for
example, the capture name biexp:
(binary_expression (number_literal) @number-in-exp) @biexp
Now we can introduce the query functions.
This function matches patterns in query within node. The argument query can be either an s-expression, a string, or a compiled query object. For now, we focus on the s-expression syntax; string syntax and compiled queries are described at the end of the section.
The argument node can also be a parser or a language symbol. A parser means use its root node, a language symbol means find or create a parser for that language in the current buffer, and use the root node.
The function returns all the captured nodes in an alist with elements
of the form (capture_name . node). If
node-only is non-nil, it returns the list of nodes
instead. By default the entire text of node is searched, but if
beg and end are both non-nil, they specify the
region of buffer text where this function should match nodes. Any
matching node whose span overlaps with the region between beg
and end is captured; it doesn’t have to be completely contained
in the region.
This function raises the treesit-query-error error if
query is malformed. The signal data contains a description of
the specific error. You can use treesit-query-validate to
validate and debug the query.
For example, suppose node’s text is 1 + 2, and
query is
(setq query
'((binary_expression
(number_literal) @number-in-exp) @biexp)
Matching that query would return
(treesit-query-capture node query)
⇒ ((biexp . <node for "1 + 2">)
(number-in-exp . <node for "1">)
(number-in-exp . <node for "2">))
As mentioned earlier, query could contain multiple patterns. For example, it could have two top-level patterns:
(setq query
'((binary_expression) @biexp
(number_literal) @number @biexp)
This function parses string as language, matches its root node with query, and returns the result.
Besides node type and capture name, tree-sitter’s pattern syntax can express anonymous node, field name, wildcard, quantification, grouping, alternation, anchor, and predicate.
An anonymous node is written verbatim, surrounded by quotes. A
pattern matching (and capturing) keyword return would be
"return" @keyword
In a pattern, ‘(_)’ matches any named node, and ‘_’ matches
any named or anonymous node. For example, to capture any named child
of a binary_expression node, the pattern would be
(binary_expression (_) @in-biexp)
It is possible to capture child nodes that have specific field names.
In the pattern below, declarator and body are field
names, indicated by the colon following them.
(function_definition declarator: (_) @func-declarator body: (_) @func-body)
It is also possible to capture a node that doesn’t have a certain
field, say, a function_definition without a body field:
(function_definition !body) @func-no-body
Tree-sitter recognizes quantification operators ‘:*’, ‘:+’, and ‘:?’. Their meanings are the same as in regular expressions: ‘:*’ matches the preceding pattern zero or more times, ‘:+’ matches one or more times, and ‘:?’ matches zero or one times.
For example, the following pattern matches type_declaration
nodes that have zero or more long keywords.
(type_declaration "long" :*) @long-type
The following pattern matches a type declaration that may or may not
have a long keyword:
(type_declaration "long" :?) @long-type
Similar to groups in regular expressions, we can bundle patterns into groups and apply quantification operators to them. For example, to express a comma-separated list of identifiers, one could write
(identifier) ("," (identifier)) :*
Again, similar to regular expressions, we can express “match any one of these patterns” in a pattern. The syntax is a vector of patterns. For example, to capture some keywords in C, the pattern would be
[ "return" "break" "if" "else" ] @keyword
The anchor operator :anchor can be used to enforce juxtaposition,
i.e., to enforce two things to be directly next to each other. The
two “things” can be two nodes, or a child and the end of its parent.
For example, to capture the first child, the last child, or two
adjacent children:
;; Anchor the child with the end of its parent. (compound_expression (_) @last-child :anchor)
;; Anchor the child with the beginning of its parent. (compound_expression :anchor (_) @first-child)
;; Anchor two adjacent children. (compound_expression (_) @prev-child :anchor (_) @next-child)
Note that the enforcement of juxtaposition ignores any anonymous nodes.
It is possible to add predicate constraints to a pattern. For example, with the following pattern:
( (array :anchor (_) @first (_) @last :anchor) (:equal @first @last) )
tree-sitter only matches arrays where the first element is equal to
the last element. To attach a predicate to a pattern, we need to
group them together. Currently there are three predicates:
:equal, :match, and :pred.
Matches if arg1 is equal to arg2. Arguments can be either strings or capture names. Capture names represent the text that the captured node spans in the buffer.
Matches if the text that capture-name’s node spans in the buffer matches regular expression regexp, given as a string literal. Matching is case-sensitive.
Matches if function fn returns non-nil when passed each
node in nodes as arguments. The function runs with the current
buffer set to the buffer of node being queried.
Note that a predicate can only refer to capture names that appear in the same pattern. Indeed, it makes little sense to refer to capture names in other patterns.
Besides s-expressions, Emacs allows the tree-sitter’s native query syntax to be used by writing them as strings. It largely resembles the s-expression syntax. For example, the following query
(treesit-query-capture
node '((addition_expression
left: (_) @left
"+" @plus-sign
right: (_) @right) @addition
["return" "break"] @keyword))
is equivalent to
(treesit-query-capture
node "(addition_expression
left: (_) @left
\"+\" @plus-sign
right: (_) @right) @addition
[\"return\" \"break\"] @keyword")
Most patterns can be written directly as s-expressions inside a string. Only a few of them need modification:
:anchor is written as ‘.’.
:equal, :match and :pred are written as
#equal, #match and #pred, respectively.
In general, predicates change their ‘:’ to ‘#’.
For example,
'(( (compound_expression :anchor (_) @first (_) :* @rest) (:match "love" @first) ))
is written in string form as
"( (compound_expression . (_) @first (_)* @rest) (#match \"love\" @first) )"
If a query is intended to be used repeatedly, especially in tight loops, it is important to compile that query, because a compiled query is much faster than an uncompiled one. A compiled query can be used anywhere a query is accepted.
This function compiles query for language into a compiled query object and returns it.
This function raises the treesit-query-error error if
query is malformed. The signal data contains a description of
the specific error. You can use treesit-query-validate to
validate and debug the query.
This function returns the language of query.
This function converts the s-expression query into the string format.
This function converts the s-expression pattern into the string format.
For more details, read the tree-sitter project’s documentation about pattern-matching, which can be found at https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries.
It’s often useful to be able to identify and find certain things in a buffer, like function and class definitions, statements, code blocks, strings, comments, etc. Emacs allows users to define what kind of tree-sitter node corresponds to a “thing”. This enables handy features like jumping to the next function, marking the code block at point, or transposing two function arguments.
The “things” feature in Emacs is independent of the pattern matching feature of tree-sitter, and comparatively less powerful, but more suitable for navigation and traversing the parse tree.
You can define things with treesit-thing-settings, retrieve the
predicate of a defined thing with treesit-thing-definition, and
test if a thing is defined with treesit-thing-defined-p.
This is an alist of thing definitions for each language. The key of
each entry is a language symbol, and the value is a list of thing
definitions of the form (thing pred), where
thing is a symbol representing the thing, like defun,
sexp, or sentence; and pred specifies what kind of
tree-sitter node is this thing.
pred can be a regexp string that matches the type of the node; it
can be a function that takes a node as the argument and returns a
boolean that indicates whether the node qualifies as the thing; or it can
be a cons (regexp . fn), which is a combination
of a regular expression regexp and a function fn—the node
has to match both the regexp and to satisfy fn to qualify as
the thing.
pred can also be recursively defined. It can be (or pred…), meaning that satisfying any one of the preds
qualifies the node as the thing. It can be (not pred),
meaning that not satisfying pred qualifies the node.
Finally, pred can refer to other things defined in this
list. For example, (or sexp sentence) defines something
that’s either a sexp thing or a sentence thing, as defined
by some other rule in the alist.
Here’s an example treesit-thing-settings for C and C++:
((c
(defun "function_definition")
(sexp (not "[](),[{}]"))
(comment "comment")
(string "raw_string_literal")
(text (or comment string)))
(cpp
(defun ("function_definition" . cpp-ts-mode-defun-valid-p))
(defclass "class_specifier")
(comment "comment")))
Note that this example is modified for didactic purposes, and isn’t
exactly how C and C++ modes define things.
Emacs builtin functions already make use some thing definitions.
Command treesit-forward-sexp uses the sexp definition if
major mode defines it; treesit-forward-sentence uses the
sentence definition. Defun movement functions like
treesit-end-of-defun uses the defun definition
(defun definition is overridden by
treesit-defun-type-regexp for backward compatibility). Major
modes can also define comment, string, text
(generally comments and strings).
The rest of this section lists a few functions that take advantage of
the thing definitions. Besides the functions below, some other
functions listed elsewhere also utilize the thing feature, e.g.,
tree-traversing functions like treesit-search-forward,
treesit-induce-sparse-tree, etc. See Retrieving Nodes.
This function checks whether node is a thing.
If node is a thing, return non-nil, otherwise return
nil. For convenience, if node is nil, this
function just returns nil.
The thing can be either a thing symbol like defun, or
simply a predicate that defines a thing, like
"function_definition", or (or comment string).
By default, if thing is undefined or malformed, this function
signals treesit-invalid-predicate error. If ignore-missing
is t, this function doesn’t signal the error when thing is
undefined and just returns nil; but it still signals the error if
thing is a malformed predicate.
This function returns the first node before position that is the
specified thing. If no such node exists, it returns nil.
It’s guaranteed that, if a node is returned, the node’s end position is
less or equal to position. In other words, this function never
returns a node that encloses position.
Again, thing can be either a symbol or a predicate.
This function is similar to treesit-thing-prev, only it returns
the first node after position that’s the thing. It
also guarantees that if a node is returned, the node’s start position is
greater or equal to position.
This function builds upon treesit-thing-prev and
treesit-thing-next and provides functionality that a navigation
command would find useful. It returns the position after moving across
arg instances of thing from position. If
there aren’t enough things to navigate across, it returns nil. The
function doesn’t move point.
A positive arg means moving forward that many instances of
thing; negative arg means moving backward. If side is
beg, this function stops at the beginning of thing; if
end, stop at the end of thing.
Like in treesit-thing-prev, thing can be a thing symbol
defined in treesit-thing-settings, or a predicate.
tactic determines how this function moves between things. It can
be nested, top-level, restricted, or nil.
nested or nil means normal nested navigation: first try to
move across siblings; if there aren’t any siblings left in the current
level, move to the parent, then its siblings, and so on.
top-level means only navigate across top-level things and ignore
nested things. restricted means movement is restricted within
the thing that encloses position, if there is such a thing. This
tactic is useful for commands that want to stop at the current nesting
level and not move up.
This function returns the smallest node that’s the thing and
encloses position; if there’s no such node, it returns nil.
The returned node must enclose position, i.e., its start position is less or equal to position, and it’s end position is greater or equal to position.
If strict is non-nil, this function uses strict comparison,
i.e., start position must be strictly greater than position, and end
position must be strictly less than position.
thing can be either a thing symbol defined in
treesit-thing-settings, or a predicate.
There are also some convenient wrapper functions.
treesit-beginning-of-thing moves point to the beginning of a
thing, treesit-end-of-thing moves to the end of a thing, and
treesit-thing-at-point returns the thing at point.
There are also defun commands that specifically use the defun
definition (as a fallback of treesit-defun-type-regexp), like
treesit-beginning-of-defun, treesit-end-of-defun, and
treesit-defun-at-point. In addition, these functions use
treesit-defun-tactic as the navigation tactic. They are
described in more detail in other sections (see Developing major modes with tree-sitter).
Sometimes, the source of a programming language could contain snippets of other languages; HTML + CSS + JavaScript is one example. In that case, text segments written in different languages need to be assigned different parsers. Traditionally, this is achieved by using narrowing. While tree-sitter works with narrowing (see narrowing), the recommended way is instead to specify regions of buffer text (i.e., ranges) in which a parser will operate. This section describes functions for setting and getting ranges for a parser.
Generally when there are multiple languages at play, there is a “primary”, or “host” language. The parser for this language—the primary parser, parses the entire buffer. Parsers for other languages are “embedded” or “guest” parsers, which only work on part of the buffer. The parse tree of the primary parser is usually used to determine the ranges in which the embedded parsers operate.
Major modes should set treesit-primary-parser to the primary
parser before calling treesit-major-mode-setup, so that Emacs can
configure the primary parser correctly for font-lock and other features.
Lisp programs should call treesit-update-ranges to make sure the
ranges for each parser are correct before using parsers in a buffer, and
call treesit-language-at to figure out the language responsible
for the text at some position. These two functions don’t work by
themselves; they need major modes to set treesit-range-settings
and treesit-language-at-point-function, which do the actual work.
These functions and variables are explained in more detail towards the
end of the section.
In short, multi-language major modes should set
treesit-primary-parser, treesit-range-settings, and
treesit-language-at-point-function before calling
treesit-major-mode-setup.
This function sets up parser to operate on ranges. The
parser will only read the text of the specified ranges. Each
range in ranges is a pair of the form (beg . end).
The ranges in ranges must come in order and must not overlap. That is, in pseudo code:
(cl-loop for idx from 1 to (1- (length ranges))
for prev = (nth (1- idx) ranges)
for next = (nth idx ranges)
should (<= (car prev) (cdr prev)
(car next) (cdr next)))
If ranges violates this constraint, or something else went
wrong, this function signals the treesit-range-invalid error.
The signal data contains a specific error message and the ranges we
are trying to set.
This function can also be used for disabling ranges. If ranges
is nil, the parser is set to parse the whole buffer.
Example:
(treesit-parser-set-included-ranges parser '((1 . 9) (16 . 24) (24 . 25)))
This function returns the ranges set for parser. The return
value is the same as the ranges argument of
treesit-parser-included-ranges: a list of cons cells of the form
(beg . end). If parser doesn’t have any
ranges, the return value is nil.
(treesit-parser-included-ranges parser)
⇒ ((1 . 9) (16 . 24) (24 . 25))
This function matches source with query and returns the
ranges of captured nodes. The return value is a list of cons cells of
the form (beg . end), where beg and
end specify the beginning and the end of a region of text.
For convenience, source can be a language symbol, a parser, or a node. If it’s a language symbol, this function matches in the root node of the first parser using that language; if a parser, this function matches in the root node of that parser; if a node, this function matches in that node.
The argument query is the query used to capture nodes
(see Pattern Matching Tree-sitter Nodes). The capture names don’t matter. The
arguments beg and end, if both non-nil, limit the
range in which this function queries.
Like other query functions, this function raises the
treesit-query-error error if query is malformed.
It should suffice for general Lisp programs to call the following two functions in order to support program sources that mix multiple languages.
This function updates ranges for parsers in the buffer. It makes sure
the parsers’ ranges are set correctly between beg and end,
according to treesit-range-settings. If omitted, beg
defaults to the beginning of the buffer, and end defaults to the
end of the buffer.
For example, fontification functions use this function before querying for nodes in a region.
This function returns the language of the text at buffer position
pos. Under the hood it calls
treesit-language-at-point-function and returns its return
value. If treesit-language-at-point-function is nil,
this function returns the language of the first parser in the returned
value of treesit-parser-list. If there is no parser in the
buffer, it returns nil.
Normally, in a set of languages that can be mixed together, there is a host language and one or more embedded languages. A Lisp program usually first parses the whole document with the host language’s parser, retrieves some information, sets ranges for the embedded languages with that information, and then parses the embedded languages.
Take a buffer containing HTML, CSS, and JavaScript
as an example. A Lisp program will first parse the whole buffer with
an HTML parser, then query the parser for
style_element and script_element nodes, which correspond
to CSS and JavaScript text, respectively. Then it sets the
range of the CSS and JavaScript parsers to the range which
their corresponding nodes span.
Given a simple HTML document:
<html>
<script>1 + 2</script>
<style>body { color: "blue"; }</style>
</html>
a Lisp program will first parse with a HTML parser, then set ranges for CSS and JavaScript parsers:
;; Create parsers. (setq html (treesit-parser-create 'html)) (setq css (treesit-parser-create 'css)) (setq js (treesit-parser-create 'javascript))
;; Set CSS ranges.
(setq css-range
(treesit-query-range
'html
'((style_element (raw_text) @capture))))
(treesit-parser-set-included-ranges css css-range)
;; Set JavaScript ranges.
(setq js-range
(treesit-query-range
'html
'((script_element (raw_text) @capture))))
(treesit-parser-set-included-ranges js js-range)
Emacs automates this process in treesit-update-ranges. A
multi-language major mode should set treesit-range-settings so
that treesit-update-ranges knows how to perform this process
automatically. Major modes should use the helper function
treesit-range-rules to generate a value that can be assigned to
treesit-range-settings. The settings in the following example
directly translate into operations shown above.
(setq treesit-range-settings
(treesit-range-rules
:embed 'javascript
:host 'html
'((script_element (raw_text) @capture))
:embed 'css
:host 'html
'((style_element (raw_text) @capture))))
;; Major modes with multiple languages should always set
;; `treesit-language-at-point-function' (which see).
(setq treesit-language-at-point-function
(lambda (pos)
(let* ((node (treesit-node-at pos 'html))
(parent (treesit-node-parent node)))
(cond
((and node parent
(equal (treesit-node-type node) "raw_text")
(equal (treesit-node-type parent) "script_element"))
'javascript)
((and node parent
(equal (treesit-node-type node) "raw_text")
(equal (treesit-node-type parent) "style_element"))
'css)
(t 'html)))))
This function is used to set treesit-range-settings. It takes
care of compiling queries and other post-processing, and outputs a
value that treesit-range-settings can have.
It takes a series of query-specs, where each query-spec is a query preceded by zero or more keyword/value pairs. Each query is a tree-sitter query in either the string, s-expression, or compiled form, or a function.
If query is a tree-sitter query, it should be preceded by two
keyword/value pairs, where the :embed keyword
specifies the embedded language, and the :host keyword
specifies the host language.
If the query is given the :local keyword whose value is
t, the range set by this query has a dedicated local parser;
otherwise the range shares a parser with other ranges for the same
language.
By default, a parser sees its ranges as a continuum, rather than treating them as separate independent segments. Therefore, if the embedded ranges are semantically independent segments, they should be processed by local parsers, described below.
Local parser set to a range can be retrieved by
treesit-local-parsers-at and treesit-local-parsers-on.
treesit-update-ranges uses query to figure out how to set
the ranges for parsers for the embedded language. It queries
query in a host language parser, computes the ranges which the
captured nodes span, and applies these ranges to embedded language
parsers.
If query is a function, it doesn’t need any keyword and value pair. It should be a function that takes 2 arguments, start and end, and sets the ranges for parsers in the current buffer in the region between start and end. It is fine for this function to set ranges in a larger region that encompasses the region between start and end.
This variable helps treesit-update-ranges in updating the
ranges for parsers in the buffer. It is a list of settings
where the exact format of a setting is considered internal. You
should use treesit-range-rules to generate a value that this
variable can have.
This variable’s value should be a function that takes a single
argument, pos, which is a buffer position, and returns the
language of the buffer text at pos. This variable is used by
treesit-language-at.
This function returns all the local parsers at pos in the current buffer. pos defaults to point.
Local parsers are those which only parse a limited region marked by an
overlay with a non-nil treesit-parser property. If
language is non-nil, only return parsers for that
language.
This function is the same as treesit-local-parsers-at, but it
returns the local parsers in the range between beg and end
instead of at point.
beg and end default to the entire accessible portion of the buffer.
This section covers some general guidelines on developing tree-sitter integration for a major mode.
A major mode supporting tree-sitter features should roughly follow this pattern:
(define-derived-mode woomy-mode prog-mode "Woomy"
"A mode for Woomy programming language."
(when (treesit-ready-p 'woomy)
(setq-local treesit-variables ...)
...
(treesit-major-mode-setup)))
treesit-ready-p automatically emits a warning if conditions for
enabling tree-sitter aren’t met.
If a tree-sitter major mode shares setup with its “native” counterpart, one can create a “base mode” that contains the common setup, like this:
(define-derived-mode woomy--base-mode prog-mode "Woomy" "An internal mode for Woomy programming language." (common-setup) ...)
(define-derived-mode woomy-mode woomy--base-mode "Woomy" "A mode for Woomy programming language." (native-setup) ...)
(define-derived-mode woomy-ts-mode woomy--base-mode "Woomy"
"A mode for Woomy programming language."
(when (treesit-ready-p 'woomy)
(setq-local treesit-variables ...)
...
(treesit-major-mode-setup)))
This function checks for conditions for activating tree-sitter. It checks whether Emacs was built with tree-sitter, whether the buffer’s size is not too large for tree-sitter to handle, and whether the grammar for language is available on the system (see Tree-sitter Language Grammar).
This function emits a warning if tree-sitter cannot be activated. If
quiet is message, the warning is turned into a message;
if quiet is t, no warning or message is displayed.
If all the necessary conditions are met, this function returns
non-nil; otherwise it returns nil.
This function activates some tree-sitter features for a major mode.
Currently, it sets up the following features:
treesit-font-lock-settings (see 基于解析器的字体锁定)
is non-nil, it sets up fontification.
treesit-simple-indent-rules or
treesit-indent-function (see 基于解析器的缩进) is
non-nil, it sets up indentation.
treesit-defun-type-regexp is non-nil, it sets up
navigation functions for beginning-of-defun and
end-of-defun.
treesit-defun-name-function is non-nil, it sets up
add-log functions used by add-log-current-defun.
treesit-simple-imenu-settings (see Imenu) is
non-nil, it sets up Imenu.
treesit-outline-predicate (see 大纲次要模式) is
non-nil, it sets up Outline minor mode.
sexp and/or sentence are defined in
treesit-thing-settings (see User-defined “Things” and Navigation), it enables
navigation commands that move, respectively, by sexps and sentences by
defining variables such as forward-sexp-function and
forward-sentence-function.
For more information on these built-in tree-sitter features, see 基于解析器的字体锁定, see 基于解析器的缩进, and see Moving over Balanced Expressions.
For supporting mixing of multiple languages in a major mode, see Parsing Text in Multiple Languages.
Besides beginning-of-defun and end-of-defun, Emacs
provides some additional functions for working with defuns:
treesit-defun-at-point returns the defun node at point, and
treesit-defun-name returns the name of a defun node.
This function returns the defun node at point, or nil if none
is found. It respects treesit-defun-tactic: if its value is
top-level, this function returns the top-level defun, and if
its value is nested, it returns the immediate enclosing defun.
This function requires treesit-defun-type-regexp to work. If
it is nil, this function simply returns nil.
This function returns the defun name of node. It returns
nil if there is no defun name for node, or if node
is not a defun node, or if node is nil.
Depending on the language and major mode, the defun names are names like function name, class name, struct name, etc.
If treesit-defun-name-function is nil, this function
always returns nil.
If non-nil, this variable’s value should be a function that is
called with a node as its argument, and returns the defun name of the
node. The function should have the same semantics as
treesit-defun-name: if the node is not a defun node, or the
node is a defun node but doesn’t have a name, or the node is
nil, it should return nil.
Emacs’s tree-sitter integration doesn’t expose every feature provided by tree-sitter’s C API. Missing features include:
In addition, Emacs makes some changes to the C API to make the API more convenient and idiomatic:
nil.
Below is the correspondence between all C API functions and their ELisp counterparts. Sometimes one ELisp function corresponds to multiple C functions, and many C functions don’t have an ELisp counterpart.
ts_parser_new treesit-parser-create ts_parser_delete ts_parser_set_language ts_parser_language treesit-parser-language ts_parser_set_included_ranges treesit-parser-set-included-ranges ts_parser_included_ranges treesit-parser-included-ranges ts_parser_parse ts_parser_parse_string treesit-parse-string ts_parser_parse_string_encoding ts_parser_reset ts_parser_set_timeout_micros ts_parser_timeout_micros ts_parser_set_cancellation_flag ts_parser_cancellation_flag ts_parser_set_logger ts_parser_logger ts_parser_print_dot_graphs ts_tree_copy ts_tree_delete ts_tree_root_node ts_tree_language ts_tree_edit ts_tree_get_changed_ranges ts_tree_print_dot_graph ts_node_type treesit-node-type ts_node_symbol ts_node_start_byte treesit-node-start ts_node_start_point ts_node_end_byte treesit-node-end ts_node_end_point ts_node_string treesit-node-string ts_node_is_null ts_node_is_named treesit-node-check ts_node_is_missing treesit-node-check ts_node_is_extra treesit-node-check ts_node_has_changes ts_node_has_error treesit-node-check ts_node_parent treesit-node-parent ts_node_child treesit-node-child ts_node_field_name_for_child treesit-node-field-name-for-child ts_node_child_count treesit-node-child-count ts_node_named_child treesit-node-child ts_node_named_child_count treesit-node-child-count ts_node_child_by_field_name treesit-node-child-by-field-name ts_node_child_by_field_id ts_node_next_sibling treesit-node-next-sibling ts_node_prev_sibling treesit-node-prev-sibling ts_node_next_named_sibling treesit-node-next-sibling ts_node_prev_named_sibling treesit-node-prev-sibling ts_node_first_child_for_byte treesit-node-first-child-for-pos ts_node_first_named_child_for_byte treesit-node-first-child-for-pos ts_node_descendant_for_byte_range treesit-node-descendant-for-range ts_node_descendant_for_point_range ts_node_named_descendant_for_byte_range treesit-node-descendant-for-range ts_node_named_descendant_for_point_range ts_node_edit ts_node_eq treesit-node-eq ts_tree_cursor_new ts_tree_cursor_delete ts_tree_cursor_reset ts_tree_cursor_current_node ts_tree_cursor_current_field_name ts_tree_cursor_current_field_id ts_tree_cursor_goto_parent ts_tree_cursor_goto_next_sibling ts_tree_cursor_goto_first_child ts_tree_cursor_goto_first_child_for_byte ts_tree_cursor_goto_first_child_for_point ts_tree_cursor_copy ts_query_new ts_query_delete ts_query_pattern_count ts_query_capture_count ts_query_string_count ts_query_start_byte_for_pattern ts_query_predicates_for_pattern ts_query_step_is_definite ts_query_capture_name_for_id ts_query_string_value_for_id ts_query_disable_capture ts_query_disable_pattern ts_query_cursor_new ts_query_cursor_delete ts_query_cursor_exec treesit-query-capture ts_query_cursor_did_exceed_match_limit ts_query_cursor_match_limit ts_query_cursor_set_match_limit ts_query_cursor_set_byte_range ts_query_cursor_set_point_range ts_query_cursor_next_match ts_query_cursor_remove_match ts_query_cursor_next_capture ts_language_symbol_count ts_language_symbol_name ts_language_symbol_for_name ts_language_field_count ts_language_field_name_for_id ts_language_field_id_for_name ts_language_symbol_type ts_language_version
An abbreviation or abbrev is a string of characters that may be expanded to a longer string. The user can insert the abbrev string and find it replaced automatically with the expansion of the abbrev. This saves typing.
The set of abbrevs currently in effect is recorded in an abbrev table. Each buffer has a local abbrev table, but normally all buffers in the same major mode share one abbrev table. There is also a global abbrev table. Normally both are used.
An abbrev table is represented as an obarray. See 创建与编入符号, for information about obarrays. Each abbreviation is represented by a symbol in the obarray. The symbol’s name is the abbreviation; its value is the expansion; its function definition is the hook function for performing the expansion (see Defining Abbrevs); and its property list cell contains various additional properties, including the use count and the number of times the abbreviation has been expanded (see Abbrev Properties).
Certain abbrevs, called system abbrevs, are defined by a major
mode instead of the user. A system abbrev is identified by its
non-nil :system property (see Abbrev Properties).
When abbrevs are saved to an abbrev file, system abbrevs are omitted.
See Saving Abbrevs in Files.
Because the symbols used for abbrevs are not interned in the usual obarray, they will never appear as the result of reading a Lisp expression; in fact, normally they are never used except by the code that handles abbrevs. Therefore, it is safe to use them in a nonstandard way.
If the minor mode Abbrev mode is enabled, the buffer-local variable
abbrev-mode is non-nil, and abbrevs are automatically
expanded in the buffer. For the user-level commands for abbrevs, see
Abbrev Mode in The GNU Emacs Manual.
This section describes how to create and manipulate abbrev tables.
This function creates and returns a new, empty abbrev table—an obarray containing no symbols. props is a property list that is applied to the new table (see Abbrev Table Properties).
This function returns a non-nil value if object is an
abbrev table.
This function undefines all the abbrevs in abbrev-table, leaving it empty.
This function returns a copy of abbrev-table—a new abbrev table containing the same abbrev definitions. It does not copy any property lists; only the names, values, and functions.
This function defines tabname (a symbol) as an abbrev table
name, i.e., as a variable whose value is an abbrev table. It defines
abbrevs in the table according to definitions, a list of
elements of the form (abbrevname expansion
[hook] [props...]). These elements are passed as
arguments to define-abbrev.
The optional string docstring is the documentation string of the variable tabname. The property list props is applied to the abbrev table (see Abbrev Table Properties).
If this function is called more than once for the same tabname, subsequent calls add the definitions in definitions to tabname, rather than overwriting the entire original contents. (A subsequent call only overrides abbrevs explicitly redefined or undefined in definitions.)
This is a list of symbols whose values are abbrev tables.
define-abbrev-table adds the new abbrev table name to this list.
This function inserts before point a description of the abbrev table named name. The argument name is a symbol whose value is an abbrev table.
If human is non-nil, the description is human-oriented.
System abbrevs are listed and identified as such. Otherwise the
description is a Lisp expression—a call to define-abbrev-table
that would define name as it is currently defined, but without
the system abbrevs. (The mode or package using name is supposed
to add these to name separately.)
define-abbrev is the low-level basic function for defining an
abbrev in an abbrev table.
When a major mode defines a system abbrev, it should call
define-abbrev and specify t for the :system
property. Be aware that any saved non-system abbrevs are restored
at startup, i.e., before some major modes are loaded. Therefore, major
modes should not assume that their abbrev tables are empty when they
are first loaded.
This function defines an abbrev named name, in
abbrev-table, to expand to expansion and call hook,
with properties props (see Abbrev Properties). The return
value is name. The :system property in props is
treated specially here: if it has the value force, then it will
overwrite an existing definition even for a non-system abbrev of
the same name.
name should be a string. The argument expansion is
normally the desired expansion (a string), or nil to undefine
the abbrev. If it is anything but a string or nil, then the
abbreviation expands solely by running hook.
The argument hook is a function or nil. If hook is
non-nil, then it is called with no arguments after the abbrev is
replaced with expansion; point is located at the end of
expansion when hook is called.
If hook is a non-nil symbol whose no-self-insert
property is non-nil, hook can explicitly control whether
to insert the self-inserting input character that triggered the
expansion. If hook returns non-nil in this case, that
inhibits insertion of the character. By contrast, if hook
returns nil, expand-abbrev (or abbrev-insert)
also returns nil, as if expansion had not really occurred.
Normally, define-abbrev sets the variable
abbrevs-changed to t, if it actually changes the abbrev.
This is so that some commands will offer to save the abbrevs. It
does not do this for a system abbrev, since those aren’t saved anyway.
If this variable is non-nil, it means that the user plans to use
global abbrevs only. This tells the commands that define mode-specific
abbrevs to define global ones instead. This variable does not alter the
behavior of the functions in this section; it is examined by their
callers.
A file of saved abbrev definitions is actually a file of Lisp code.
The abbrevs are saved in the form of a Lisp program to define the same
abbrev tables with the same contents. Therefore, you can load the file
with load (see 程序的加载方式). However, the
function quietly-read-abbrev-file is provided as a more
convenient interface. Emacs automatically calls this function at
startup.
User-level facilities such as save-some-buffers can save
abbrevs in a file automatically, under the control of variables
described here.
This is the default file name for reading and saving abbrevs. By default, Emacs will look for ~/.emacs.d/abbrev_defs, and, if not found, for ~/.abbrev_defs; if neither file exists, Emacs will create ~/.emacs.d/abbrev_defs.
This function reads abbrev definitions from a file named filename,
previously written with write-abbrev-file. If filename is
omitted or nil, the file specified in abbrev-file-name is
used.
As the name implies, this function does not display any messages.
A non-nil value for save-abbrevs means that Emacs should
offer to save abbrevs (if any have changed) when files are saved. If
the value is silently, Emacs saves the abbrevs without asking
the user. abbrev-file-name specifies the file to save the
abbrevs in. The default value is t.
This variable is set non-nil by defining or altering any
abbrevs (except system abbrevs). This serves as a flag for various
Emacs commands to offer to save your abbrevs.
Save all abbrev definitions (except system abbrevs), for all abbrev
tables listed in abbrev-table-name-list, in the file
filename, in the form of a Lisp program that when loaded will
define the same abbrevs. Tables that do not have any abbrevs to save
are omitted. If filename is nil or omitted,
abbrev-file-name is used. This function returns nil.
Abbrevs are usually expanded by certain interactive commands,
including self-insert-command. This section describes the
subroutines used in writing such commands, as well as the variables they
use for communication.
This function returns the symbol representing the abbrev named
abbrev. It returns nil if that abbrev is not
defined. The optional second argument table is the abbrev table
in which to look it up. If table is nil, this function
tries first the current buffer’s local abbrev table, and second the
global abbrev table.
This function returns the string that abbrev would expand into (as
defined by the abbrev tables used for the current buffer). It returns
nil if abbrev is not a valid abbrev.
The optional argument table specifies the abbrev table to use,
as in abbrev-symbol.
This command expands the abbrev before point, if any. If point does not
follow an abbrev, this command does nothing. To do the expansion, it
calls the function that is the value of the abbrev-expand-function
variable, with no arguments, and returns whatever that function does.
The default expansion function returns the abbrev symbol if it did
expansion, and nil otherwise. If the abbrev symbol has a hook
function that is a symbol whose no-self-insert property is
non-nil, and if the hook function returns nil as its
value, then the default expansion function returns nil,
even though expansion did occur.
This function inserts the abbrev expansion of abbrev, replacing
the text between start and end. If start is
omitted, it defaults to point. name, if non-nil, should
be the name by which this abbrev was found (a string); it is used to
figure out whether to adjust the capitalization of the expansion. The
function returns abbrev if the abbrev was successfully
inserted, otherwise it returns nil.
This command marks the current location of point as the beginning of
an abbrev. The next call to expand-abbrev will use the text
from here to point (where it is then) as the abbrev to expand, rather
than using the previous word as usual.
First, this command expands any abbrev before point, unless arg
is non-nil. (Interactively, arg is the prefix argument.)
Then it inserts a hyphen before point, to indicate the start of the
next abbrev to be expanded. The actual expansion removes the hyphen.
When this is set non-nil, an abbrev entered entirely in upper
case is expanded using all upper case. Otherwise, an abbrev entered
entirely in upper case is expanded by capitalizing each word of the
expansion.
The value of this variable is a buffer position (an integer or a marker)
for expand-abbrev to use as the start of the next abbrev to be
expanded. The value can also be nil, which means to use the
word before point instead. abbrev-start-location is set to
nil each time expand-abbrev is called. This variable is
also set by abbrev-prefix-mark.
The value of this variable is the buffer for which
abbrev-start-location has been set. Trying to expand an abbrev
in any other buffer clears abbrev-start-location. This variable
is set by abbrev-prefix-mark.
This is the abbrev-symbol of the most recent abbrev expanded. This
information is left by expand-abbrev for the sake of the
unexpand-abbrev command (see Expanding
Abbrevs in The GNU Emacs Manual).
This is the location of the most recent abbrev expanded. This contains
information left by expand-abbrev for the sake of the
unexpand-abbrev command.
This is the exact expansion text of the most recent abbrev expanded,
after case conversion (if any). Its value is nil if the abbrev
has already been unexpanded. This contains information left by
expand-abbrev for the sake of the unexpand-abbrev command.
The value of this variable is a function that expand-abbrev
will call with no arguments to do the expansion. The function can do
anything it wants before and after performing the expansion.
It should return the abbrev symbol if expansion took place.
The following sample code shows a simple use of
abbrev-expand-function. It assumes that foo-mode is a
mode for editing certain files in which lines that start with ‘#’
are comments. You want to use Text mode abbrevs for those lines. The
regular local abbrev table, foo-mode-abbrev-table is
appropriate for all other lines. See Standard Abbrev Tables, for the
definitions of local-abbrev-table and text-mode-abbrev-table.
See 为 Emacs Lisp 函数添加建议, for details of add-function.
(defun foo-mode-abbrev-expand-function (expand)
(if (not (save-excursion (forward-line 0) (eq (char-after) ?#)))
;; Performs normal expansion.
(funcall expand)
;; We're inside a comment: use the text-mode abbrevs.
(let ((local-abbrev-table text-mode-abbrev-table))
(funcall expand))))
(add-hook 'foo-mode-hook
(lambda ()
(add-function :around (local 'abbrev-expand-function)
#'foo-mode-abbrev-expand-function)))
Here we list the variables that hold the abbrev tables for the preloaded major modes of Emacs.
This is the abbrev table for mode-independent abbrevs. The abbrevs defined in it apply to all buffers. Each buffer may also have a local abbrev table, whose abbrev definitions take precedence over those in the global table.
The value of this buffer-local variable is the (mode-specific) abbreviation table of the current buffer. It can also be a list of such tables.
The value of this variable is a list of elements of the form
(mode . abbrev-table) where mode is the name
of a variable: if the variable is bound to a non-nil value,
then the abbrev-table is active, otherwise it is ignored.
abbrev-table can also be a list of abbrev tables.
This is the local abbrev table used in Fundamental mode; in other words, it is the local abbrev table in all buffers in Fundamental mode.
This is the local abbrev table used in Text mode.
This is the local abbrev table used in Lisp mode. It is the parent of the local abbrev table used in Emacs Lisp mode. See Abbrev Table Properties.
Abbrevs have properties, some of which influence the way they work.
You can provide them as arguments to define-abbrev, and
manipulate them with the following functions:
Set the property prop of abbrev to value val.
Return the property prop of abbrev, or nil if the
abbrev has no such property.
The following properties have special meanings:
:countThis property counts the number of times the abbrev has
been expanded. If not explicitly set, it is initialized to 0 by
define-abbrev.
:systemIf non-nil, this property marks the abbrev as a system abbrev.
Such abbrevs are not saved (see Saving Abbrevs in Files).
:enable-functionIf non-nil, this property should be a function of no
arguments which returns nil if the abbrev should not be used
and t otherwise.
:case-fixedIf non-nil, this property indicates that the case of the
abbrev’s name is significant and should only match a text with the
same pattern of capitalization. It also disables the code that
modifies the capitalization of the expansion.
Like abbrevs, abbrev tables have properties, some of which influence
the way they work. You can provide them as arguments to
define-abbrev-table, and manipulate them with the functions:
Set the property prop of abbrev table table to value val.
Return the property prop of abbrev table table, or nil
if table has no such property.
The following properties have special meaning:
:enable-functionThis is like the :enable-function abbrev property except that
it applies to all abbrevs in the table. It is used before even trying
to find the abbrev before point, so it can dynamically modify the
abbrev table.
:case-fixedThis is like the :case-fixed abbrev property except that it
applies to all abbrevs in the table.
:regexpIf non-nil, this property is a regular expression that
indicates how to extract the name of the abbrev before point, before
looking it up in the table. When the regular expression matches
before point, the abbrev name is expected to be in submatch 1.
If this property is nil, the default is to use
backward-word and forward-word to find the name. This
property allows the use of abbrevs whose name contains characters of
non-word syntax.
:parentsThis property holds a list of tables from which to inherit other abbrevs.
:abbrev-table-modiffThis property holds a counter incremented each time a new abbrev is added to the table.
Emacs Lisp provides a limited form of concurrency, called threads. All the threads in a given instance of Emacs share the same memory. Concurrency in Emacs Lisp is “mostly cooperative”, meaning that Emacs will only switch execution between threads at well-defined times. However, the Emacs thread support has been designed in a way to later allow more fine-grained concurrency, and correct programs should not rely on cooperative threading.
Currently, thread switching will occur upon explicit request via
thread-yield, when waiting for keyboard input or for process
output from asynchronous processes (e.g., during
accept-process-output), or during blocking operations relating
to threads, such as mutex locking or thread-join.
Emacs Lisp provides primitives to create and control threads, and also to create and control mutexes and condition variables, useful for thread synchronization.
While global variables are shared among all Emacs Lisp threads,
local variables are not—a dynamic let binding is local. Each
thread also has its own current buffer (see The Current Buffer) and
its own match data (see The Match Data).
Note that let bindings are treated specially by the Emacs
Lisp implementation. There is no way to duplicate this unwinding and
rewinding behavior other than by using let. For example, a
manual implementation of let written using
unwind-protect cannot arrange for variable values to be
thread-specific.
In the case of lexical bindings (see Scoping 变量绑定的作用域规则), a closure is an object like any other in Emacs Lisp, and bindings in a closure are shared by any threads invoking the closure.
Threads can be created and waited for. A thread cannot be exited directly, but the current thread can be exited implicitly, and other threads can be signaled.
Create a new thread of execution which invokes function. When function returns, the thread exits.
The new thread is created with no local variable bindings in effect. The new thread’s current buffer is inherited from the current thread.
name can be supplied to give a name to the thread. The name is used for debugging and informational purposes only; it has no meaning to Emacs. If name is provided, it must be a string.
This function returns the new thread.
This function returns t if object represents an Emacs
thread, nil otherwise.
Block until thread exits, or until the current thread is signaled. It returns the result of the thread function. If thread has already exited, this returns immediately.
Like signal (see 如何发出错误信号), but the signal is
delivered in the thread thread. If thread is the current
thread, then this just calls signal immediately. Otherwise,
thread will receive the signal as soon as it becomes current.
If thread was blocked by a call to mutex-lock,
condition-wait, or thread-join; thread-signal
will unblock it.
If thread is the main thread, the signal is not propagated there. Instead, it is shown as message in the main thread.
Yield execution to the next runnable thread.
Return the name of thread, as specified to make-thread.
Return t if thread is alive, or nil if it is not.
A thread is alive as long as its function is still executing.
Return the object that thread is waiting on. This function is primarily intended for debugging, and is given a “double hyphen” name to indicate that.
If thread is blocked in thread-join, this returns the
thread for which it is waiting.
If thread is blocked in mutex-lock, this returns the mutex.
If thread is blocked in condition-wait, this returns the
condition variable.
Otherwise, this returns nil.
Return the current thread.
Return a list of all the live thread objects. A new list is returned by each invocation.
This variable keeps the main thread Emacs is running, or nil if
Emacs is compiled without thread support.
When code run by a thread signals an error that is unhandled, the thread exits. Other threads can access the error form which caused the thread to exit using the following function.
This function returns the last error form recorded when a thread
exited due to an error. Each thread that exits abnormally overwrites
the form stored by the previous thread’s error with a new value, so
only the last one can be accessed. If cleanup is
non-nil, the stored form is reset to nil.
A mutex is an exclusive lock. At any moment, zero or one threads may own a mutex. If a thread attempts to acquire a mutex, and the mutex is already owned by some other thread, then the acquiring thread will block until the mutex becomes available.
Emacs Lisp mutexes are of a type called recursive, which means that a thread can re-acquire a mutex it owns any number of times. A mutex keeps a count of how many times it has been acquired, and each acquisition of a mutex must be paired with a release. The last release by a thread of a mutex reverts it to the unowned state, potentially allowing another thread to acquire the mutex.
This function returns t if object represents an Emacs
mutex, nil otherwise.
Create a new mutex and return it. If name is specified, it is a name given to the mutex. It must be a string. The name is for debugging purposes only; it has no meaning to Emacs.
Return the name of mutex, as specified to make-mutex.
This will block until this thread acquires mutex, or until this
thread is signaled using thread-signal. If mutex is
already owned by this thread, this simply returns.
Release mutex. If mutex is not owned by this thread, this will signal an error.
This macro is the simplest and safest way to evaluate forms while holding a mutex. It acquires mutex, invokes body, and then releases mutex. It returns the result of body.
A condition variable is a way for a thread to block until some event occurs. A thread can wait on a condition variable, to be woken up when some other thread notifies the condition.
A condition variable is associated with a mutex and, conceptually, with some condition. For proper operation, the mutex must be acquired, and then a waiting thread must loop, testing the condition and waiting on the condition variable. For example:
(with-mutex mutex
(while (not global-variable)
(condition-wait cond-var)))
The mutex ensures atomicity, and the loop is for robustness—there may be spurious notifications.
Similarly, the mutex must be held before notifying the condition. The typical, and best, approach is to acquire the mutex, make the changes associated with this condition, and then notify it:
(with-mutex mutex (setq global-variable (some-computation)) (condition-notify cond-var))
Make a new condition variable associated with mutex. If name is specified, it is a name given to the condition variable. It must be a string. The name is for debugging purposes only; it has no meaning to Emacs.
This function returns t if object represents a condition
variable, nil otherwise.
Wait for another thread to notify cond, a condition variable.
This function will block until the condition is notified, or until a
signal is delivered to this thread using thread-signal.
It is an error to call condition-wait without holding the
condition’s associated mutex.
condition-wait releases the associated mutex while waiting.
This allows other threads to acquire the mutex in order to notify the
condition.
Notify cond. The mutex with cond must be held before
calling this. Ordinarily a single waiting thread is woken by
condition-notify; but if all is not nil, then all
threads waiting on cond are notified.
condition-notify releases the associated mutex.
This allows other threads to acquire the mutex in order to wait on the
condition.
Return the name of cond, as passed to
make-condition-variable.
Return the mutex associated with cond. Note that the associated mutex cannot be changed.
The list-threads command lists all the currently alive threads.
In the resulting buffer, each thread is identified either by the name
passed to make-thread (see Basic Thread Functions), or by
its unique internal identifier if it was not created with a name. The
status of each thread at the time of the creation or last update of
the buffer is shown, in addition to the object the thread was blocked
on at the time, if it was blocked.
The *Threads* buffer will automatically update twice per second. You can make the refresh rate faster or slower by customizing this variable.
Here are the commands available in the thread list buffer:
Show a backtrace of the thread at point. This will show where in its code the thread had yielded or was blocked at the moment you pressed b. Be aware that the backtrace is a snapshot; the thread could have meanwhile resumed execution, and be in a different state, or could have exited.
You may use g in the thread’s backtrace buffer to get an updated backtrace, as backtrace buffers do not automatically update. See 调用栈, for a description of backtraces and the other commands which work on them.
Signal the thread at point. After s, type q to send a quit signal or e to send an error signal. Threads may implement handling of signals, but the default behavior is to exit on any signal. Therefore you should only use this command if you understand how to restart the target thread, because your Emacs session may behave incorrectly if necessary threads are killed.
Update the list of threads and their statuses.
In the terminology of operating systems, a process is a space in which a program can execute. Emacs runs in a process. Emacs Lisp programs can invoke other programs in processes of their own. These are called subprocesses or child processes of the Emacs process, which is their parent process.
A subprocess of Emacs may be synchronous or asynchronous, depending on how it is created. When you create a synchronous subprocess, the Lisp program waits for the subprocess to terminate before continuing execution. When you create an asynchronous subprocess, it can run in parallel with the Lisp program. This kind of subprocess is represented within Emacs by a Lisp object which is also called a “process”. Lisp programs can use this object to communicate with the subprocess or to control it. For example, you can send signals, obtain status information, receive output from the process, or send input to it.
In addition to processes that run programs, Lisp programs can open connections of several types to devices or processes running on the same machine or on other machines. The supported connection types are: TCP and UDP network connections, serial port connections, and pipe connections. Each such connection is also represented by a process object.
This function returns t if object represents an Emacs
process object, nil otherwise. The process object can
represent a subprocess running a program or a connection of any
supported type.
In addition to subprocesses of the current Emacs session, you can also access other processes running on your machine. See Accessing Other Processes.
There are three primitives that create a new subprocess in which to run
a program. One of them, make-process, creates an asynchronous
process and returns a process object (see Creating an Asynchronous Process).
The other two, call-process and call-process-region,
create a synchronous process and do not return a process object
(see Creating a Synchronous Process). There are various higher-level
functions that make use of these primitives to run particular types of
process.
Synchronous and asynchronous processes are explained in the following sections. Since the three functions are all called in a similar fashion, their common arguments are described here.
In all cases, the functions specify the program to be run. An error
is signaled if the file is not found or cannot be executed. If the
file name is relative, the variable exec-path contains a list
of directories to search. Emacs initializes exec-path when it
starts up, based on the value of the environment variable PATH.
The standard file name constructs, ‘~’, ‘.’, and ‘..’,
are interpreted as usual in exec-path, but environment variable
substitutions (‘$HOME’, etc.) are not recognized; use
substitute-in-file-name to perform them (see 文件名展开相关函数). nil in this list refers to
default-directory.
Executing a program can also try adding suffixes to the specified name:
This variable is a list of suffixes (strings) to try adding to the
specified program file name. The list should include "" if you
want the name to be tried exactly as specified. The default value is
system-dependent.
Please note: The argument program contains only the name of the program file; it may not contain any command-line arguments. You must use a separate argument, args, to provide those, as described below.
Each of the subprocess-creating functions has a buffer-or-name
argument that specifies where the output from the program will go. It
should be a buffer or a buffer name; if it is a buffer name, that will
create the buffer if it does not already exist. It can also be
nil, which says to discard the output, unless a custom filter
function handles it. (See Process Filter Functions, and Lisp 对象的读取与打印.) Normally, you should avoid having multiple processes send
output to the same buffer because their output would be intermixed
randomly. For synchronous processes, you can send the output to a
file instead of a buffer (and the corresponding argument is therefore
more appropriately called destination). By default, both
standard output and standard error streams go to the same destination,
but all the 3 primitives allow optionally to direct the standard error
stream to a different destination.
All three of the subprocess-creating functions allow specifying
command-line arguments for the process to run. For call-process
and call-process-region, these come in the form of a
&rest argument, args. For make-process, both the
program to run and its command-line arguments are specified as a list
of strings. The command-line arguments must all be strings, and they
are supplied to the program as separate argument strings. Wildcard
characters and other shell constructs have no special meanings in
these strings, since the strings are passed directly to the specified
program.
The subprocess inherits its environment from Emacs, but you can
specify overrides for it with process-environment. See Operating System Environment. The subprocess gets its current directory from the
value of default-directory.
The value of this variable is a string, the name of a directory that
contains programs that come with GNU Emacs and are intended for Emacs
to invoke. The program movemail is an example of such a program;
Rmail uses it to fetch new mail from an inbox.
The value of this variable is a list of directories to search for
programs to run in subprocesses. Each element is either the name of a
directory (i.e., a string), or nil, which stands for the default
directory (which is the value of default-directory).
See executable-find, for the details of this search.
The value of exec-path is used by call-process and
start-process when the program argument is not an absolute
file name.
Generally, you should not modify exec-path directly. Instead,
ensure that your PATH environment variable is set appropriately
before starting Emacs. Trying to modify exec-path
independently of PATH can lead to confusing results.
This function is an extension of the variable exec-path. If
default-directory indicates a remote directory, this function
returns a list of directories used for searching programs on the
respective remote host. In case of a local default-directory,
the function returns just the value of the variable exec-path.
When starting a program that is part of the Emacs distribution, you must take into account that the program may have been renamed in order to comply with executable naming restrictions present on the system.
Instead of starting ctags, for example, you should specify
the value of ctags-program-name instead. Likewise, instead of
starting movemail, you must start
movemail-program-name, and the same goes for etags,
hexl, emacsclient, rcs2log, and
ebrowse.
Lisp programs sometimes need to run a shell and give it a command
that contains file names that were specified by the user. These
programs ought to be able to support any valid file name. But the shell
gives special treatment to certain characters, and if these characters
occur in the file name, they will confuse the shell. To handle these
characters, use the function shell-quote-argument:
This function returns a string that represents, in shell syntax, an argument whose actual contents are argument. It should work reliably to concatenate the return value into a shell command and then pass it to a shell for execution.
Precisely what this function does depends on your operating system. The function is designed to work with the syntax of your system’s standard shell; if you use an unusual shell, you will need to redefine this function. See Security Considerations.
;; This example shows the behavior on GNU and Unix systems. (shell-quote-argument "foo > bar") ⇒ "foo\\ \\>\\ bar" ;; This example shows the behavior on MS-DOS and MS-Windows. (shell-quote-argument "foo > bar") ⇒ "\"foo > bar\""
Here’s an example of using shell-quote-argument to construct
a shell command:
(concat "diff -u "
(shell-quote-argument oldfile)
" "
(shell-quote-argument newfile))
If the optional posix argument is non-nil, argument
is quoted according to POSIX shell quoting rules, regardless of the
system’s shell. This is useful when your shell could run on a remote
host, which requires a POSIX shell in general.
(shell-quote-argument "foo > bar" (file-remote-p default-directory))
The following two functions are useful for combining a list of
individual command-line argument strings into a single string, and
taking a string apart into a list of individual command-line
arguments. These functions are mainly intended for converting user
input in the minibuffer, a Lisp string, into a list of string
arguments to be passed to make-process, call-process or
start-process, or for converting such lists of arguments into a
single Lisp string to be presented in the minibuffer or echo area.
Note that if a shell is involved (e.g., if using
call-process-shell-command), arguments should still be
protected by shell-quote-argument;
combine-and-quote-strings is not intended to protect
special characters from shell evaluation.
This function splits string into substrings, respecting double and single quotes, as well as backslash quoting.
(split-string-shell-command "ls /tmp/'foo bar'")
⇒ ("ls" "/tmp/foo bar")
This function splits string into substrings at matches for the
regular expression separators, like split-string does
(see 创建字符串); in addition, it removes quoting from the
substrings. It then makes a list of the substrings and returns it.
If separators is omitted or nil, it defaults to
"\\s-+", which is a regular expression that matches one or more
characters with whitespace syntax (see Table of Syntax Classes).
This function supports two types of quoting: enclosing a whole string
in double quotes "…", and quoting individual characters
with a backslash escape ‘\’. The latter is also used in Lisp
strings, so this function can handle those as well.
This function concatenates list-of-strings into a single string,
quoting each string as necessary. It also sticks the separator
string between each pair of strings; if separator is omitted or
nil, it defaults to " ". The return value is the
resulting string.
The strings in list-of-strings that need quoting are those that
include separator as their substring. Quoting a string encloses
it in double quotes "…". In the simplest case, if you
are consing a command from the individual command-line arguments,
every argument that includes embedded blanks will be quoted.
After a synchronous process is created, Emacs waits for the
process to terminate before continuing. Starting Dired on GNU or
Unix29 is an example of this: it
runs ls in a synchronous process, then modifies the output
slightly. Because the process is synchronous, the entire directory
listing arrives in the buffer before Emacs tries to do anything with it.
While Emacs waits for the synchronous subprocess to terminate, the
user can quit by typing C-g. The first C-g tries to kill
the subprocess with a SIGINT signal; but it waits until the
subprocess actually terminates before quitting. If during that time the
user types another C-g, that kills the subprocess instantly with
SIGKILL and quits immediately (except on MS-DOS, where killing
other processes doesn’t work). See 退出.
The synchronous subprocess functions return an indication of how the process terminated.
The output from a synchronous subprocess is generally decoded using a
coding system, much like text read from a file. The input sent to a
subprocess by call-process-region is encoded using a coding
system, much like text written into a file. See Coding Systems.
This function calls program and waits for it to finish.
The current working directory of the subprocess is set to the current
buffer’s value of default-directory if that is local (as
determined by unhandled-file-name-directory), or "~" otherwise.
If you want to run a process in a remote directory use
process-file.
The standard input for the new process comes from file infile if
infile is not nil, and from the null device otherwise.
The argument destination says where to put the process output.
Here are the possibilities:
Insert the output in that buffer, before point. This includes both the standard output stream and the standard error stream of the process.
Insert the output in a buffer with that name, before point.
tInsert the output in the current buffer, before point.
nilDiscard the output.
Discard the output, and return nil immediately without waiting
for the subprocess to finish.
In this case, the process is not truly synchronous, since it can run in parallel with Emacs; but you can think of it as synchronous in that Emacs is essentially finished with the subprocess as soon as this function returns.
MS-DOS doesn’t support asynchronous subprocesses, so this option doesn’t work there.
(:file file-name)Send the output to the file name specified, overwriting it if it already exists.
(real-destination error-destination)Keep the standard output stream separate from the standard error stream;
deal with the ordinary output as specified by real-destination,
and dispose of the error output according to error-destination.
If error-destination is nil, that means to discard the
error output, t means mix it with the ordinary output, and a
string specifies a file name to redirect error output into.
You can’t directly specify a buffer to put the error output in; that is too difficult to implement. But you can achieve this result by sending the error output to a temporary file and then inserting the file into a buffer when the subprocess finishes.
If display is non-nil, then call-process redisplays
the buffer as output is inserted. (However, if the coding system chosen
for decoding output is undecided, meaning deduce the encoding
from the actual data, then redisplay sometimes cannot continue once
non-ASCII characters are encountered. There are fundamental
reasons why it is hard to fix this; see Receiving Output from Processes.)
Otherwise the function call-process does no redisplay, and the
results become visible on the screen only when Emacs redisplays that
buffer in the normal course of events.
The remaining arguments, args, are strings that specify command line arguments for the program. Each string is passed to program as a separate argument.
The value returned by call-process (unless you told it not to
wait) indicates the reason for process termination. A number gives the
exit status of the subprocess; 0 means success, and any other value
means failure. If the process terminated with a signal,
call-process returns a string describing the signal. If you
told call-process not to wait, it returns nil.
In the examples below, the buffer ‘foo’ is current.
(call-process "pwd" nil t)
⇒ 0
---------- Buffer: foo ----------
/home/lewis/manual
---------- Buffer: foo ----------
(call-process "grep" nil "bar" nil "lewis" "/etc/passwd")
⇒ 0
---------- Buffer: bar ----------
lewis:x:1001:1001:Bil Lewis,,,,:/home/lewis:/bin/bash
---------- Buffer: bar ----------
Here is an example of the use of call-process, as used to
be found in the definition of the insert-directory function:
(call-process insert-directory-program nil t nil switches
(if full-directory-p
(concat (file-name-as-directory file) ".")
file))
This function processes files synchronously in a separate process. It
is similar to call-process, but may invoke a file name handler
based on the value of the variable default-directory, which
specifies the current working directory of the subprocess.
The arguments are handled in almost the same way as for
call-process, with the following differences:
Some file name handlers may not support all combinations and forms of the
arguments infile, buffer, and display. For example,
some file name handlers might behave as if display were nil,
regardless of the value actually passed. As another example, some
file name handlers might not support separating standard output and error
output by way of the buffer argument.
If a file name handler is invoked, it determines the program to run based
on the first argument program. For instance, suppose that a
handler for remote files is invoked. Then the path that is used for
searching for the program might be different from exec-path.
The second argument infile may invoke a file name handler. The file
name handler could be different from the handler chosen for the
process-file function itself. (For example,
default-directory could be on one remote host, and
infile on a different remote host. Or default-directory
could be non-special, whereas infile is on a remote host.)
If buffer is a list of the form (real-destination
error-destination), and error-destination names a file,
then the same remarks as for infile apply.
The remaining arguments (args) will be passed to the process
verbatim. Emacs is not involved in processing file names that are
present in args. To avoid confusion, it may be best to avoid
absolute file names in args, but rather to specify all file
names as relative to default-directory. The function
file-relative-name is useful for constructing such relative
file names. Alternatively, you can use file-local-name
(see 实现“魔法”文件名机制) to obtain an absolute file name as seen
from the remote host’s perspective.
This variable indicates whether a call of process-file changes
remote files.
By default, this variable is always set to t, meaning that a
call of process-file could potentially change any file on a
remote host. When set to nil, a file name handler could optimize
its behavior with respect to remote file attribute caching.
You should only ever change this variable with a let-binding; never
with setq.
This user option indicates whether a call of process-file
returns a string describing the signal interrupting a remote process.
When a process returns an exit code greater than 128, it is
interpreted as a signal. process-file requires returning a
string describing this signal.
Since there are processes violating this rule, returning exit codes
greater than 128 which are not bound to a signal, process-file
returns always the exit code as natural number for remote processes.
Setting this user option to non-nil forces process-file to
interpret such exit codes as signals, and to return a corresponding
string.
This function sends the text from start to end as
standard input to a process running program. It deletes the text
sent if delete is non-nil; this is useful when
destination is t, to insert the output in the current
buffer in place of the input.
The arguments destination and display control what to do
with the output from the subprocess, and whether to update the display
as it comes in. For details, see the description of
call-process, above. If destination is the integer 0,
call-process-region discards the output and returns nil
immediately, without waiting for the subprocess to finish (this only
works if asynchronous subprocesses are supported; i.e., not on MS-DOS).
The remaining arguments, args, are strings that specify command line arguments for the program.
The return value of call-process-region is just like that of
call-process: nil if you told it to return without
waiting; otherwise, a number or string which indicates how the
subprocess terminated.
In the following example, we use call-process-region to run the
cat utility, with standard input being the first five characters
in buffer ‘foo’ (the word ‘input’). cat copies its
standard input into its standard output. Since the argument
destination is t, this output is inserted in the current
buffer.
---------- Buffer: foo ---------- input∗ ---------- Buffer: foo ----------
(call-process-region 1 6 "cat" nil t)
⇒ 0
---------- Buffer: foo ----------
inputinput∗
---------- Buffer: foo ----------
For example, the shell-command-on-region command uses
call-shell-region in a manner similar to this:
(call-shell-region
start end
command ; shell command
nil ; do not delete region
buffer) ; send output to buffer
This function executes the shell command command synchronously.
The other arguments are handled as in call-process. An old
calling convention allowed passing any number of additional arguments
after display, which were concatenated to command; this is
still supported, but strongly discouraged.
This function is like call-process-shell-command, but uses
process-file internally. Depending on default-directory,
command can be executed also on remote hosts. An old calling
convention allowed passing any number of additional arguments after
display, which were concatenated to command; this is still
supported, but strongly discouraged.
This function sends the text from start to end as
standard input to an inferior shell running command. This function
is similar than call-process-region, with process being a shell.
The arguments delete, destination and the return value
are like in call-process-region.
Note that this function doesn’t accept additional arguments.
If command names a shell (e.g., via shell-file-name), keep
in mind that behavior of various shells when commands are piped to their
standard input is shell- and system-dependent, and thus non-portable.
The differences are especially prominent when the region includes more
than one line, i.e. when piping to a shell commands with embedded
newlines. Lisp programs using this technique will therefore need to
format the text in the region differently, according to the expectations
of the shell.
This function executes command (a string) as a shell command,
then returns the command’s output as a string. If command
actually includes more than one command, the behavior depends on the
shell to be invoked (determined by shell-file-name for local
commands). In particular, the separator between the commands cannot be
a newline on MS-Windows; use ‘&&’ instead.
This function runs program, waits for it to finish, and returns its output as a list of strings. Each string in the list holds a single line of text output by the program; the end-of-line characters are stripped from each line. The arguments beyond program, args, are strings that specify command-line arguments with which to run the program.
If program exits with a non-zero exit status, this function signals an error.
This function works by calling call-process, so program output
is decoded in the same way as for call-process.
This function is just like process-lines, but does not signal
an error if program exits with a non-zero exit status.
In this section, we describe how to create an asynchronous process. After an asynchronous process is created, it runs in parallel with Emacs, and Emacs can communicate with it using the functions described in the following sections (see Sending Input to Processes, and see Receiving Output from Processes). Note that process communication is only partially asynchronous: Emacs sends and receives data to and from a process only when those functions are called.
An asynchronous process is controlled either via a pty
(pseudo-terminal) or a pipe. The choice of pty or pipe is made
when creating the process, by default based on the value of the
variable process-connection-type (see below). If available,
ptys are usually preferable for processes visible to the user, as in
Shell mode, because they allow for job control (C-c, C-z,
etc.) between the process and its children, and because interactive
programs treat ptys as terminal devices, whereas pipes don’t support
these features. However, for subprocesses used by Lisp programs for
internal purposes (i.e., no user interaction with the subprocess is
required), where significant amounts of data need to be exchanged
between the subprocess and the Lisp program, it is often better to use
a pipe, because pipes are more efficient. Also, the total number of
ptys is limited on many systems, and it is good not to waste them
unnecessarily.
This function is the basic low-level primitive for starting
asynchronous subprocesses. It returns a process object representing
the subprocess. Compared to the more high-level start-process,
described below, it takes keyword arguments, is more flexible, and
enables you to specify process filters and sentinels in a single call.
The arguments args are a list of keyword/argument pairs.
Omitting a keyword is always equivalent to specifying it with value
nil. Here are the meaningful keywords:
:name nameUse the string name as the process name; if a process with this name already exists, then name is modified (by appending ‘<1>’, etc.) to be unique.
:buffer bufferUse buffer as the process buffer. If the value is nil,
the subprocess is not associated with any buffer.
:command commandUse command as the command line of the process. The value
should be a list starting with the program’s executable file name,
followed by strings to give to the program as its arguments. If
the first element of the list is nil, Emacs opens a new
pseudoterminal (pty) and associates its input and output with
buffer, without actually running any program; the rest of the
list elements are ignored in that case.
:coding codingIf coding is a symbol, it specifies the coding system to be
used for both reading and writing of data from and to the
connection. If coding is a cons cell
(decoding . encoding), then decoding
will be used for reading and encoding for writing. The coding
system used for encoding the data written to the program is also used
for encoding the command-line arguments (but not the program itself,
whose file name is encoded as any other file name; see file-name-coding-system).
If coding is nil, the default rules for finding the
coding system will apply. See Default Coding Systems.
:connection-type typeInitialize the type of device used to communicate with the subprocess.
Possible values are pty to use a pty, pipe to use a
pipe, or nil to use the default derived from the value of the
process-connection-type variable. If type is a cons cell
(input . output), then input will be used
for standard input and output for standard output (and standard
error if :stderr is nil).
On systems where ptys are not available (MS-Windows), this parameter is ignored, and pipes are used unconditionally.
:noquery query-flagInitialize the process query flag to query-flag. See Querying Before Exit.
:stop stoppedIf provided, stopped must be nil; it is an error to use
any non-nil value. The :stop key is ignored otherwise
and is retained for compatibility with other process types such as
pipe processes. Asynchronous subprocesses never start in the stopped
state.
:filter filterInitialize the process filter to filter. If not specified, a default filter will be provided, which can be overridden later. See Process Filter Functions.
:sentinel sentinelInitialize the process sentinel to sentinel. If not specified, a default sentinel will be used, which can be overridden later. See Sentinels: Detecting Process Status Changes.
:stderr stderrAssociate stderr with the standard error of the process. A
non-nil value should be either a buffer or a pipe process
created with make-pipe-process, described below. If
stderr is nil, standard error is mixed with standard
output, and both are sent to buffer or filter.
If stderr is a buffer, Emacs will create a pipe process, the
standard error process. This process will have the default
filter (see Process Filter Functions), sentinel (see Sentinels: Detecting Process Status Changes), and
coding systems (see Default Coding Systems). On the other hand,
it will use query-flag as its query-on-exit flag (see Querying Before Exit). It will be associated with the stderr buffer
(see Process Buffers) and send its output (which is the standard
error of the main process) there. To get the process object for the
standard error process, pass the stderr buffer to
get-buffer-process.
If stderr is a pipe process, Emacs will use it as standard error process for the new process.
:file-handler file-handlerIf file-handler is non-nil, then look for a file name
handler for the current buffer’s default-directory, and invoke
that file name handler to make the process. If there is no such
handler, proceed as if file-handler were nil.
The original argument list, modified with the actual connection
information, is available via the process-contact function.
The current working directory of the subprocess is set to the current
buffer’s value of default-directory if that is local (as
determined by unhandled-file-name-directory), or ~
otherwise. If you want to run a process in a remote directory, pass
:file-handler t to make-process. In that case, the
current working directory is the local name component of
default-directory (as determined by file-local-name).
Depending on the implementation of the file name handler, it might not
be possible to apply filter or sentinel to the resulting
process object. The :stderr argument cannot be a pipe process,
file name handlers do not support pipe processes for this. A buffer
as :stderr argument is accepted, its contents is shown without
the use of pipe processes. See Process Filter Functions, Sentinels: Detecting Process Status Changes,
and Accepting Output from Processes.
Some file name handlers may not support make-process. In such
cases, this function does nothing and returns nil.
This function creates a bidirectional pipe which can be attached to a
child process. This is useful with the :stderr keyword of
make-process. The function returns a process object.
The arguments args are a list of keyword/argument pairs.
Omitting a keyword is always equivalent to specifying it with value
nil.
Here are the meaningful keywords:
:name nameUse the string name as the process name. As with
make-process, it is modified if necessary to make it unique.
:buffer bufferUse buffer as the process buffer.
:coding codingIf coding is a symbol, it specifies the coding system to be
used for both reading and writing of data from and to the
connection. If coding is a cons cell
(decoding . encoding), then decoding
will be used for reading and encoding for writing.
If coding is nil, the default rules for finding the
coding system will apply. See Default Coding Systems.
:noquery query-flagInitialize the process query flag to query-flag. See Querying Before Exit.
:stop stoppedIf stopped is non-nil, start the process in the stopped
state. In the stopped state, a pipe process does not accept incoming
data, but you can send outgoing data. The stopped state is set by
stop-process and cleared by continue-process
(see Sending Signals to Processes).
:filter filterInitialize the process filter to filter. If not specified, a default filter will be provided, which can be changed later. See Process Filter Functions.
:sentinel sentinelInitialize the process sentinel to sentinel. If not specified, a default sentinel will be used, which can be changed later. See Sentinels: Detecting Process Status Changes.
The original argument list, modified with the actual connection
information, is available via the process-contact function.
This function is a higher-level wrapper around make-process,
exposing an interface that is similar to call-process. It
creates a new asynchronous subprocess and starts the specified
program running in it. It returns a process object that stands
for the new subprocess in Lisp. The argument name specifies the
name for the process object; as with make-process, it is
modified if necessary to make it unique. The buffer
buffer-or-name is the buffer to associate with the process.
If program is nil, Emacs opens a new pseudoterminal (pty)
and associates its input and output with buffer-or-name, without
creating a subprocess. In that case, the remaining arguments
args are ignored.
The rest of args are strings that specify command line arguments for the subprocess.
In the example below, the first process is started and runs (rather, sleeps) for 100 seconds (the output buffer ‘foo’ is created immediately). Meanwhile, the second process is started, and given the name ‘my-process<1>’ for the sake of uniqueness. It inserts the directory listing at the end of the buffer ‘foo’, before the first process finishes. Then it finishes, and a message to that effect is inserted in the buffer. Much later, the first process finishes, and another message is inserted in the buffer for it.
(start-process "my-process" "foo" "sleep" "100")
⇒ #<process my-process>
(start-process "my-process" "foo" "ls" "-l" "/bin")
⇒ #<process my-process<1>>
---------- Buffer: foo ----------
total 8336
-rwxr-xr-x 1 root root 971384 Mar 30 10:14 bash
-rwxr-xr-x 1 root root 146920 Jul 5 2011 bsd-csh
...
-rwxr-xr-x 1 root root 696880 Feb 28 15:55 zsh4
Process my-process<1> finished
Process my-process finished
---------- Buffer: foo ----------
Like start-process, this function starts a new asynchronous
subprocess running program in it, and returns its process
object.
The difference from start-process is that this function may
invoke a file name handler based on the value of default-directory.
This handler ought to run program, perhaps on the local host,
perhaps on a remote host that corresponds to default-directory.
In the latter case, the local part of default-directory becomes
the working directory of the process.
This function does not try to invoke file name handlers for
program or for the rest of args. For that reason, if
program or any of args use the remote-file syntax
(see 实现“魔法”文件名机制), they must be converted either to file
names relative to default-directory, or to names that identify
the files locally on the remote host, by running them through
file-local-name.
Depending on the implementation of the file name handler, it might not be
possible to apply process-filter or process-sentinel to
the resulting process object. See Process Filter Functions, and Sentinels: Detecting Process Status Changes.
Some file name handlers may not support start-file-process (for
example the function ange-ftp-hook-function). In such cases,
this function does nothing and returns nil.
This function is like start-process, except that it uses a
shell to execute the specified command. The argument
command is a shell command string. The variable
shell-file-name specifies which shell to use.
The point of running a program through the shell, rather than directly
with make-process or start-process, is so that you can
employ shell features such as wildcards in the arguments. It follows
that if you include any arbitrary user-specified arguments in the
command, you should quote them with shell-quote-argument first,
so that any special shell characters do not have their special
shell meanings. See Shell Arguments. Of course, when executing
commands based on user input you should also consider the security
implications.
This function is like start-process-shell-command, but uses
start-file-process internally. Because of this, command
can also be executed on remote hosts, depending on default-directory.
This variable controls the type of device used to communicate with
asynchronous subprocesses. If it is non-nil, then ptys are
used, when available. Otherwise, pipes are used.
The value of process-connection-type takes effect when
make-process or start-process is called. So you can
specify how to communicate with one subprocess by binding the variable
around the call to these functions.
Note that the value of this variable is ignored when
make-process is called with a non-nil value of the
:stderr parameter; in that case, Emacs will communicate with
the process using pipes. It is also ignored if ptys are unavailable
(MS-Windows).
(let ((process-connection-type nil)) ; use a pipe
(start-process ...))
To determine whether a given subprocess actually got a pipe or a pty,
use the function process-tty-name (see Process Information).
If a process sentinel/filter function has an error, Emacs will (by
default) pause Emacs for process-error-pause-time seconds after
displaying this error, so that users will see the error in question.
However, this can lead to situations where Emacs becomes unresponsive
(if there’s a lot of these errors happening), so this can be disabled
by setting process-error-pause-time to 0.
Deleting a process disconnects Emacs immediately from the subprocess. Processes are deleted automatically after they terminate, but not necessarily right away. You can delete a process explicitly at any time. If you explicitly delete a terminated process before it is deleted automatically, no harm results. Deleting a running process sends a signal to terminate it (and its child processes, if any), and calls the process sentinel. See Sentinels: Detecting Process Status Changes.
When a process is deleted, the process object itself continues to exist as long as other Lisp objects point to it. All the Lisp primitives that work on process objects accept deleted processes, but those that do I/O or send signals will report an error. The process mark continues to point to the same place as before, usually into a buffer where output from the process was being inserted.
This variable controls automatic deletion of processes that have
terminated (due to calling exit or to a signal). If it is
nil, then they continue to exist until the user runs
list-processes. Otherwise, they are deleted immediately after
they exit.
This function deletes a process, killing it with a SIGKILL
signal if the process was running a program. The argument may be a
process, the name of a process, a buffer, or the name of a buffer. (A
buffer or buffer-name stands for the process that
get-buffer-process returns, and a missing or nil
process means that the current buffer’s process should be
killed.) Calling delete-process on a running process
terminates it, updates the process status, and runs the sentinel
immediately. If the process has already terminated, calling
delete-process has no effect on its status, or on the running
of its sentinel (which will happen sooner or later).
If the process object represents a network, serial, or pipe
connection, its status changes to closed; otherwise, it changes
to signal, unless the process already exited. See process-status.
(delete-process "*shell*")
⇒ nil
Several functions return information about processes.
This command displays a listing of all living processes. In addition,
it finally deletes any process whose status was ‘Exited’ or
‘Signaled’. It returns nil.
The processes are shown in a buffer named *Process List* (unless you specify otherwise using the optional argument buffer), whose major mode is Process Menu mode.
If query-only is non-nil, it only lists processes
whose query flag is non-nil. See Querying Before Exit.
This function returns a list of all processes that have not been deleted.
(process-list)
⇒ (#<process display-time> #<process shell>)
This function returns the number of processors, a positive integer.
Each usable thread execution unit counts as a processor.
By default, the count includes the number of available processors,
which you can override by setting the
OMP_NUM_THREADS environment variable of OpenMP.
If the optional argument query is current,
this function ignores OMP_NUM_THREADS;
if query is all, this function also counts processors
that are on the system but are not available to the current process.
This function returns the process named name (a string), or
nil if there is none. The argument name can also be a
process object, in which case it is returned.
(get-process "shell")
⇒ #<process shell>
This function returns the command that was executed to start
process. This is a list of strings, the first string being the
program executed and the rest of the strings being the arguments that
were given to the program. For a network, serial, or pipe connection,
this is either nil, which means the process is running or
t (process is stopped).
(process-command (get-process "shell"))
⇒ ("bash" "-i")
This function returns information about how a network, a serial, or a
pipe connection was set up. When key is nil, it returns
(hostname service) for a network connection,
(port speed) for a serial connection, and t
for a pipe connection. For an ordinary child process, this function
always returns t when called with a nil key.
If key is t, the value is the complete status information
for the connection, server, serial port, or pipe; that is, the list of
keywords and values specified in make-network-process,
make-serial-process, or make-pipe-process, except that
some of the values represent the current status instead of what you
specified.
For a network process, the values include (see
make-network-process for a complete list):
:bufferThe associated value is the process buffer.
:filterThe associated value is the process filter function. See Process Filter Functions.
:sentinelThe associated value is the process sentinel function. See Sentinels: Detecting Process Status Changes.
:remoteIn a connection, the address in internal format of the remote peer.
:localThe local address, in internal format.
:serviceIn a server, if you specified t for service,
this value is the actual port number.
:local and :remote are included even if they were not
specified explicitly in make-network-process.
For a serial connection, see make-serial-process and
serial-process-configure for the list of keys. For a pipe
connection, see make-pipe-process for the list of keys.
If key is a keyword, the function returns the value corresponding to that keyword.
If process is a non-blocking network stream that hasn’t been
fully set up yet, then this function will block until that has
happened. If given the optional no-block parameter, this
function will return nil instead of blocking.
This function returns the PID of process. This is an
integral number that distinguishes the process process from all
other processes running on the same computer at the current time. The
PID of a process is chosen by the operating system kernel
when the process is started and remains constant as long as the
process exists. For network, serial, and pipe connections, this
function returns nil.
This function returns the name of process, as a string.
This function returns the status of process-name as a symbol. The argument process-name must be a process, a buffer, or a process name (a string).
The possible values for an actual subprocess are:
runfor a process that is running.
stopfor a process that is stopped but continuable.
exitfor a process that has exited.
signalfor a process that has received a fatal signal.
openfor a network, serial, or pipe connection that is open.
closedfor a network, serial, or pipe connection that is closed. Once a connection is closed, you cannot reopen it, though you might be able to open a new connection to the same place.
connectfor a non-blocking connection that is waiting to complete.
failedfor a non-blocking connection that has failed to complete.
listenfor a network server that is listening.
nilif process-name is not the name of an existing process.
(process-status (get-buffer "*shell*"))
⇒ run
For a network, serial, or pipe connection, process-status
returns one of the symbols open, stop, or closed.
The latter means that the other side closed the connection, or Emacs
did delete-process. The value stop means that
stop-process was called on the connection.
This function returns non-nil if process is alive. A
process is considered alive if its status is run, open,
listen, connect or stop.
This function returns the symbol network for a network
connection or server, serial for a serial port connection,
pipe for a pipe connection, or real for a subprocess
created for running a program.
This function returns the exit status of process or the signal
number that killed it. (Use the result of process-status to
determine which of those it is.) If process has not yet
terminated, the value is 0. For network, serial, and pipe connections
that are already closed, the value is either 0 or 256, depending on
whether the connection was closed normally or abnormally.
This function returns the terminal name that process is using for
its communication with Emacs—or nil if it is using pipes
instead of a pty (see process-connection-type in
Creating an Asynchronous Process). By default, this function returns the
terminal name if any of process’s standard streams use a
terminal. If stream is one of stdin, stdout, or
stderr, this function returns the terminal name (or nil,
as above) that process uses for that stream specifically. You
can use this to determine whether a particular stream uses a pipe or a
pty.
If process represents a program running on a remote host, this
function returns the local terminal name that communicates with
process; you can get the terminal name used by that program on
the remote host with the process property remote-tty. If
process represents a network, serial, or pipe connection, this
function always returns nil.
This function returns a cons cell (decode . encode),
describing the coding systems in use for decoding output from, and
encoding input to, process (see Coding Systems).
This function specifies the coding systems to use for subsequent output from and input to process. It will use decoding-system to decode subprocess output, and encoding-system to encode subprocess input.
Every process also has a property list that you can use to store miscellaneous values associated with the process.
This function returns the value of the propname property of process.
This function sets the value of the propname property of process to value.
This function returns the process plist of process.
This function sets the process plist of process to plist.
Asynchronous subprocesses receive input when it is sent to them by Emacs, which is done with the functions in this section. You must specify the process to send input to, and the input data to send. If the subprocess runs a program, the data appears on the standard input of that program; for connections, the data is sent to the connected device or program.
Some operating systems have limited space for buffered input in a pty. On these systems, Emacs sends an EOF periodically amidst the other characters, to force them through. For most programs, these EOFs do no harm.
Subprocess input is normally encoded using a coding system before the
subprocess receives it, much like text written into a file. You can use
set-process-coding-system to specify which coding system to use
(see Process Information). Otherwise, the coding system comes from
coding-system-for-write, if that is non-nil; or else from
the defaulting mechanism (see Default Coding Systems).
Sometimes the system is unable to accept input for that process, because the input buffer is full. When this happens, the send functions wait a short while, accepting output from subprocesses, and then try again. This gives the subprocess a chance to read more of its pending input and make space in the buffer. It also allows filters (including the one currently running), sentinels and timers to run—so take account of that in writing your code.
In these functions, the process argument can be a process or
the name of a process, or a buffer or buffer name (which stands
for a process via get-buffer-process). nil means
the current buffer’s process.
This function sends process the contents of string as
standard input. It returns nil. For example, to make a
Shell buffer list files:
(process-send-string "shell<1>" "ls\n")
⇒ nil
This function sends the text in the region defined by start and end as standard input to process.
An error is signaled unless both start and end are integers or markers that indicate positions in the current buffer. (It is unimportant which number is larger.)
This function makes process see an end-of-file in its input. The EOF comes after any text already sent to it. The function returns process.
(process-send-eof "shell")
⇒ "shell"
This function will tell you whether a process, which must not be
a connection but a real subprocess, has given control of its terminal
to a child process of its own. If this is true, the function returns
the numeric ID of the foreground process group of process; it
returns nil if Emacs can be certain that this is not so. The
value is t if Emacs cannot tell whether this is true. This
function signals an error if process is a network, serial, or
pipe connection, or if the subprocess is not active.
Sending a signal to a subprocess is a way of interrupting its
activities. There are several different signals, each with its own
meaning. The set of signals and their names is defined by the operating
system. For example, the signal SIGINT means that the user has
typed C-c, or that some analogous thing has happened.
Each signal has a standard effect on the subprocess. Most signals kill the subprocess, but some stop (or resume) execution instead. Most signals can optionally be handled by programs; if the program handles the signal, then we can say nothing in general about its effects.
You can send signals explicitly by calling the functions in this
section. Emacs also sends signals automatically at certain times:
killing a buffer sends a SIGHUP signal to all its associated
processes; killing Emacs sends a SIGHUP signal to all remaining
processes. (SIGHUP is a signal that usually indicates that the
user “hung up the phone”, i.e., disconnected.)
Each of the signal-sending functions takes two optional arguments: process and current-group.
The argument process must be either a process, a process
name, a buffer, a buffer name, or nil. A buffer or buffer name
stands for a process through get-buffer-process. nil
stands for the process associated with the current buffer. Except
with stop-process and continue-process, an error is
signaled if process does not identify an active process, or if
it represents a network, serial, or pipe connection.
The argument current-group is a flag that makes a difference
when you are running a job-control shell as an Emacs subprocess. If it
is non-nil, then the signal is sent to the current process-group
of the terminal that Emacs uses to communicate with the subprocess. If
the process is a job-control shell, this means the shell’s current
subjob. If current-group is nil, the signal is
sent to the process group of the immediate subprocess of Emacs. If
the subprocess is a job-control shell, this is the shell itself. If
current-group is lambda, the signal is sent to the
process-group that owns the terminal, but only if it is not the shell
itself.
The flag current-group has no effect when a pipe is used to
communicate with the subprocess, because the operating system does not
support the distinction in the case of pipes. For the same reason,
job-control shells won’t work when a pipe is used. See
process-connection-type in Creating an Asynchronous Process.
This function interrupts the process process by sending the
signal SIGINT. Outside of Emacs, typing the interrupt
character (normally C-c on some systems, and DEL on
others) sends this signal. When the argument current-group is
non-nil, you can think of this function as typing C-c
on the terminal by which Emacs talks to the subprocess.
This command kills the process process by sending the
signal SIGKILL. This signal kills the subprocess immediately,
and cannot be handled by the subprocess. Interactively, it’ll prompt
the user for a process name, defaulting to the process (if any) in the
current buffer.
This function sends the signal SIGQUIT to the process
process. This signal is the one sent by the quit
character (usually C-\) when you are not inside
Emacs.
This function stops the specified process. If it is a real
subprocess running a program, it sends the signal SIGTSTP to
that subprocess. If process represents a network, serial, or
pipe connection, this function inhibits handling of the incoming data
from the connection; for a network server, this means not accepting
new connections. Use continue-process to resume normal
execution.
Outside of Emacs, on systems with job control, the stop character
(usually C-z) normally sends the SIGTSTP signal to a
subprocess. When current-group is non-nil, you can think
of this function as typing C-z on the terminal Emacs uses to
communicate with the subprocess.
This function resumes execution of the process process. If it
is a real subprocess running a program, it sends the signal
SIGCONT to that subprocess; this presumes that process
was stopped previously. If process represents a network,
serial, or pipe connection, this function resumes handling of the
incoming data from the connection. For serial connections, data that
arrived during the time the process was stopped might be lost.
This function sends a signal to process process. The argument signal specifies which signal to send; it should be an integer, or a symbol whose name is a signal.
The process argument can be a system process ID (an integer); that allows you to send signals to processes that are not children of Emacs. See Accessing Other Processes.
If process is a process object which contains the property
remote-pid, or process is a number and remote is a
remote file name, process is interpreted as process on the
respective remote host, which will be the process to signal.
If process is a string, it is interpreted as process object with the respective process name, or as a number.
Sometimes, it is necessary to send a signal to a non-local
asynchronous process. This is possible by writing an own
interrupt-process or signal-process implementation.
This function must be added then to interrupt-process-functions
or signal-process-functions, respectively.
This variable is a list of functions to be called for
interrupt-process. The arguments of the functions are the same
as for interrupt-process. These functions are called in the
order of the list, until one of them returns non-nil. The
default function, which shall always be the last in this list, is
internal-default-interrupt-process.
This is the mechanism, how Tramp implements interrupt-process.
This variable is a list of functions to be called for
signal-process. The arguments of the functions are the same as
for signal-process. These functions are called in the order of
the list, until one of them returns non-nil. The default
function, which shall always be the last in this list, is
internal-default-signal-process.
This is the mechanism, how Tramp implements signal-process.
The output that an asynchronous subprocess writes to its standard output stream is passed to a function called the filter function. The default filter function simply inserts the output into a buffer, which is called the associated buffer of the process (see Process Buffers). If the process has no buffer then the default filter discards the output.
If the subprocess writes to its standard error stream, by default
the error output is also passed to the process filter function.
Alternatively, you could use the :stderr parameter with a
non-nil value in a call to make-process
(see make-process) to make the destination
of the error output separate from the standard output.
When a subprocess terminates, Emacs reads any pending output, then stops reading output from that subprocess. Therefore, if the subprocess has children that are still live and still producing output, Emacs won’t receive that output.
Output from a subprocess can arrive only while Emacs is waiting: when
reading terminal input (see the function waiting-for-user-input-p),
in sit-for and sleep-for (see 等待时间流逝或输入), in
accept-process-output (see Accepting Output from Processes), and in
functions which send data to processes (see Sending Input to Processes).
This minimizes the problem of timing errors that usually plague parallel
programming. For example, you can safely create a process and only
then specify its buffer or filter function; no output can arrive
before you finish, if the code in between does not call any primitive
that waits.
On some systems, when Emacs reads the output from a subprocess, the
output data is read in very small blocks, potentially resulting in
very poor performance. This behavior can be remedied to some extent
by setting the variable process-adaptive-read-buffering to a
non-nil value (the default), as it will automatically delay reading
from such processes, thus allowing them to produce more output before
Emacs tries to read it.
A process can (and usually does) have an associated buffer, which is an ordinary Emacs buffer that is used for two purposes: storing the output from the process, and deciding when to kill the process. You can also use the buffer to identify a process to operate on, since in normal practice only one process is associated with any given buffer. Many applications of processes also use the buffer for editing input to be sent to the process, but this is not built into Emacs Lisp.
By default, process output is inserted in the associated buffer.
(You can change this by defining a custom filter function,
see Process Filter Functions.) The position to insert the output is
determined by the process-mark, which is then updated to point
to the end of the text just inserted. Usually, but not always, the
process-mark is at the end of the buffer.
Killing the associated buffer of a process also kills the process.
Emacs asks for confirmation first, if the process’s
process-query-on-exit-flag is non-nil (see Querying Before Exit). This confirmation is done by the function
process-kill-buffer-query-function, which is run from
kill-buffer-query-functions (see Killing Buffers).
This function returns the associated buffer of the specified process.
(process-buffer (get-process "shell"))
⇒ #<buffer *shell*>
This function returns the process marker for process, which is the marker that says where to insert output from the process.
If process does not have a buffer, process-mark returns a
marker that points nowhere.
The default filter function uses this marker to decide where to insert process output, and updates it to point after the inserted text. That is why successive batches of output are inserted consecutively.
Custom filter functions normally should use this marker in the same fashion.
For an example of a filter function that uses process-mark,
see Process Filter Example.
When the user is expected to enter input in the process buffer for transmission to the process, the process marker separates the new input from previous output.
This function sets the buffer associated with process to
buffer. If buffer is nil, the process becomes
associated with no buffer; if non-nil and different from the
buffer associated with the process, the process mark will be set to
point to the end of buffer (unless the process mark is already
associated with buffer).
This function returns a nondeleted process associated with the buffer
specified by buffer-or-name. If there are several processes
associated with it, this function chooses one (currently, the one most
recently created, but don’t count on that). Deletion of a process
(see delete-process) makes it ineligible for this function to
return.
It is usually a bad idea to have more than one process associated with the same buffer.
(get-buffer-process "*shell*")
⇒ #<process shell>
Killing the process’s buffer deletes the process, which kills the
subprocess with a SIGHUP signal (see Sending Signals to Processes).
If the process’s buffer is displayed in a window, your Lisp program may wish to tell the process the dimensions of that window, so that the process could adapt its output to those dimensions, much as it adapts to the screen dimensions. The following functions allow communicating this kind of information to processes; however, not all systems support the underlying functionality, so it is best to provide fallbacks, e.g., via command-line arguments or environment variables.
Tell process that its logical window size has dimensions
width by height, in character units. If this function
succeeds in communicating this information to the process, it returns
t; otherwise it returns nil.
When windows that display buffers associated with process change their
dimensions, the affected processes should be told about these changes.
By default, when the window configuration changes, Emacs will
automatically call set-process-window-size on behalf of every
process whose buffer is displayed in a window, passing it the smallest
dimensions of all the windows displaying the process’s buffer. This
works via window-configuration-change-hook (see Hooks for Window Scrolling and Changes), which is told to invoke the function that is the value of
the variable window-adjust-process-window-size-function for
each process whose buffer is displayed in at least one window. You
can customize this behavior by setting the value of that variable.
The value of this variable should be a function of two arguments: a
process and the list of windows displaying the process’s buffer. When
the function is called, the process’s buffer is the current buffer.
The function should return a cons cell (width . height) that describes the dimensions of the logical process
window to be passed via a call to set-process-window-size. The
function can also return nil, in which case Emacs will not call
set-process-window-size for this process.
Emacs supplies two predefined values for this variable:
window-adjust-process-window-size-smallest, which returns the
smallest of all the dimensions of the windows that display a process’s
buffer; and window-adjust-process-window-size-largest, which
returns the largest dimensions. For more complex strategies, write
your own function.
This variable can be buffer-local.
If the process has the adjust-window-size-function property
(see Process Information), its value overrides the global and
buffer-local values of
window-adjust-process-window-size-function.
A process filter function is a function that receives the standard output from the associated process. All output from that process is passed to the filter. The default filter simply outputs directly to the process buffer.
By default, the error output from the process, if any, is also passed to the filter function, unless the destination for the standard error stream of the process was separated from the standard output when the process was created. Emacs will only call the filter function during certain function calls. See Receiving Output from Processes. Note that if any of those functions are called by the filter, the filter may be called recursively.
A filter function must accept two arguments: the associated process and a string, which is output just received from it. The function is then free to do whatever it chooses with the output.
Quitting is normally inhibited within a filter function—otherwise,
the effect of typing C-g at command level or to quit a user
command would be unpredictable. If you want to permit quitting inside
a filter function, bind inhibit-quit to nil. In most
cases, the right way to do this is with the macro
with-local-quit. See 退出.
If an error happens during execution of a filter function, it is
caught automatically, so that it doesn’t stop the execution of whatever
program was running when the filter function was started. However, if
debug-on-error is non-nil, errors are not caught.
This makes it possible to use the Lisp debugger to debug filter
functions. See Lisp 调试器. If an error is caught, Emacs pauses for
process-error-pause-time seconds so that the user sees the
error. See Creating an Asynchronous Process.
Many filter functions sometimes (or always) insert the output in the process’s buffer, mimicking the actions of the default filter. Such filter functions need to make sure that they save the current buffer, select the correct buffer (if different) before inserting output, and then restore the original buffer. They should also check whether the buffer is still alive, update the process marker, and in some cases update the value of point. Here is how to do these things:
(defun ordinary-insertion-filter (proc string)
(when (buffer-live-p (process-buffer proc))
(with-current-buffer (process-buffer proc)
(let ((moving (= (point) (process-mark proc))))
(save-excursion
;; Insert the text, advancing the process marker.
(goto-char (process-mark proc))
(insert string)
(set-marker (process-mark proc) (point)))
(if moving (goto-char (process-mark proc)))))))
To make the filter force the process buffer to be visible whenever new
text arrives, you could insert a line like the following just before the
with-current-buffer construct:
(display-buffer (process-buffer proc))
To force point to the end of the new output, no matter where it was
previously, eliminate the variable moving from the example and
call goto-char unconditionally. Note that this doesn’t
necessarily move the window point. The default filter actually uses
insert-before-markers which moves all markers, including the
window point. This may move unrelated markers, so it’s generally
better to move the window point explicitly, or set its insertion type
to t (see Windows and Point).
Note that Emacs automatically saves and restores the match data while executing filter functions. See The Match Data.
The output to the filter may come in chunks of any size. A program that produces the same output twice in a row may send it as one batch of 200 characters one time, and five batches of 40 characters the next. If the filter looks for certain text strings in the subprocess output, make sure to handle the case where one of these strings is split across two or more batches of output; one way to do this is to insert the received text into a temporary buffer, which can then be searched.
This function gives process the filter function filter.
If filter is nil, it gives the process the default
filter, which inserts the process output into the process buffer. If
filter is t, Emacs stops accepting output from the
process, unless it’s a network server process that listens for
incoming connections.
This function returns the filter function of process.
In case the process’s output needs to be passed to several filters, you can
use add-function to combine an existing filter with a new one.
See 为 Emacs Lisp 函数添加建议.
Here is an example of the use of a filter function:
(defun keep-output (process output)
(setq kept (cons output kept)))
⇒ keep-output
(setq kept nil)
⇒ nil
(set-process-filter (get-process "shell") 'keep-output)
⇒ keep-output
(process-send-string "shell" "ls ~/other\n")
⇒ nil
kept
⇒ ("lewis@slug:$ "
"FINAL-W87-SHORT.MSS backup.otl kolstad.mss~ address.txt backup.psf kolstad.psf backup.bib~ david.mss resume-Dec-86.mss~ backup.err david.psf resume-Dec.psf backup.mss dland syllabus.mss " "#backups.mss# backup.mss~ kolstad.mss ")
When Emacs writes process output directly into a multibyte buffer,
it decodes the output according to the process output coding system.
If the coding system is raw-text or no-conversion, Emacs
converts the unibyte output to multibyte using
string-to-multibyte, and inserts the resulting multibyte text.
You can use set-process-coding-system to specify which coding
system to use (see Process Information). Otherwise, the coding
system comes from coding-system-for-read, if that is
non-nil; or else from the defaulting mechanism (see Default Coding Systems). If the text output by a process contains null
bytes, Emacs by default uses no-conversion for it; see
inhibit-null-byte-detection, for how to
control this behavior.
Warning: Coding systems such as undecided, which
determine the coding system from the data, do not work entirely
reliably with asynchronous subprocess output. This is because Emacs
has to process asynchronous subprocess output in batches, as it
arrives. Emacs must try to detect the proper coding system from one
batch at a time, and this does not always work. Therefore, if at all
possible, specify a coding system that determines both the character
code conversion and the end of line conversion—that is, one like
latin-1-unix, rather than undecided or latin-1.
When Emacs calls a process filter function, it provides the process
output as a multibyte string or as a unibyte string according to the
process’s filter coding system. Emacs
decodes the output according to the process output coding system,
which usually produces a multibyte string, except for coding systems
such as binary and raw-text.
Output from asynchronous subprocesses normally arrives only while Emacs is waiting for some sort of external event, such as elapsed time or terminal input. Occasionally it is useful in a Lisp program to explicitly permit output to arrive at a specific point, or even to wait until output arrives from a process.
This function allows Emacs to read pending output from processes. The
output is given to their filter functions. If process is
non-nil then this function does not return until some output
has been received from process or process has closed the
connection.
The arguments seconds and millisec let you specify timeout
periods. The former specifies a period measured in seconds and the
latter specifies one measured in milliseconds. The two time periods
thus specified are added together, and accept-process-output
returns after that much time, even if there is no
subprocess output.
The argument millisec is obsolete (and should not be used), because seconds can be floating point to specify waiting a fractional number of seconds. If seconds is 0, the function accepts whatever output is pending but does not wait.
If process is a process, and the argument just-this-one is
non-nil, only output from that process is handled, suspending output
from other processes until some output has been received from that
process or the timeout expires. If just-this-one is an integer,
also inhibit running timers. This feature is generally not
recommended, but may be necessary for specific applications, such as
speech synthesis.
The function accept-process-output returns non-nil if it
got output from process, or from any process if process is
nil; this can occur even after a process has exited if the
corresponding connection contains buffered data. The function returns
nil if the timeout expired or the connection was closed before output
arrived.
If a connection from a process contains buffered data,
accept-process-output can return non-nil even after the
process has exited. Therefore, although the following loop:
;; This loop contains a bug. (while (process-live-p process) (accept-process-output process))
will often read all output from process, it has a race condition
and can miss some output if process-live-p returns nil
while the connection still contains data. Better is to write the loop
like this:
(while (accept-process-output process))
If you have passed a non-nil stderr to
make-process, it will have a standard error process.
See Creating an Asynchronous Process. In that case, waiting for process
output from the main process doesn’t wait for output from the standard
error process. To make sure you have received both all of standard
output and all of standard error from a process, use the following
code:
(while (accept-process-output process)) (while (accept-process-output stderr-process))
If you passed a buffer to the stderr argument of
make-process, you still have to wait for the standard error
process, like so:
(let* ((stdout (generate-new-buffer "stdout"))
(stderr (generate-new-buffer "stderr"))
(process (make-process :name "test"
:command '("my-program")
:buffer stdout
:stderr stderr))
(stderr-process (get-buffer-process stderr)))
(unless (and process stderr-process)
(error "Process unexpectedly nil"))
(while (accept-process-output process))
(while (accept-process-output stderr-process)))
Only when both accept-process-output forms return nil,
you can be sure that the process has exited and Emacs has read all its
output.
Reading pending standard error from a process running on a remote host is not possible this way.
Because threads were a relatively late addition to Emacs Lisp, and
due to the way dynamic binding was sometimes used in conjunction with
accept-process-output, by default a process is locked to the
thread that created it. When a process is locked to a thread, output
from the process can only be accepted by that thread.
A Lisp program can specify to which thread a process is to be
locked, or instruct Emacs to unlock a process, in which case its
output can be processed by any thread. Only a single thread will wait
for output from a given process at one time—once one thread begins
waiting for output, the process is temporarily locked until
accept-process-output or sit-for returns.
If the thread exits, all the processes locked to it are unlocked.
Return the thread to which process is locked. If process
is unlocked, return nil.
Set the locking thread of process to thread. thread
may be nil, in which case the process is unlocked.
A process sentinel is a function that is called whenever the associated process changes status for any reason, including signals (whether sent by Emacs or caused by the process’s own actions) that terminate, stop, or continue the process. The process sentinel is also called if the process exits. The sentinel receives two arguments: the process for which the event occurred, and a string describing the type of event.
If no sentinel function was specified for a process, it will use the default sentinel function, which inserts a message in the process’s buffer with the process name and the string describing the event.
The string describing the event looks like one of the following (but this is not an exhaustive list of event strings):
"finished\n".
"deleted\n".
"exited abnormally with code exitcode (core dumped)\n".
The “core dumped” part is optional, and only appears if the process
dumped core.
"failed with code fail-code\n".
"signal-description (core dumped)\n". The
signal-description is a system-dependent textual description of
a signal, e.g., "killed" for SIGKILL. The “core
dumped” part is optional, and only appears if the process dumped
core.
"open from host-name\n".
"open\n".
"run\n".
"connection broken by remote peer\n".
A sentinel runs only while Emacs is waiting (e.g., for terminal
input, or for time to elapse, or for process output). This avoids the
timing errors that could result from running sentinels at random places in
the middle of other Lisp programs. A program can wait, so that
sentinels will run, by calling sit-for or sleep-for
(see 等待时间流逝或输入), or accept-process-output (see Accepting Output from Processes). Emacs also allows sentinels to run when the command loop is
reading input. delete-process calls the sentinel when it
terminates a running process.
Emacs does not keep a queue of multiple reasons to call the sentinel of one process; it records just the current status and the fact that there has been a change. Therefore two changes in status, coming in quick succession, can call the sentinel just once. However, process termination will always run the sentinel exactly once. This is because the process status can’t change again after termination.
Emacs explicitly checks for output from the process before running the process sentinel. Once the sentinel runs due to process termination, no further output can arrive from the process.
A sentinel that writes the output into the buffer of the process
should check whether the buffer is still alive. If it tries to insert
into a dead buffer, it will get an error. If the buffer is dead,
(buffer-name (process-buffer process)) returns nil.
Quitting is normally inhibited within a sentinel—otherwise, the
effect of typing C-g at command level or to quit a user command
would be unpredictable. If you want to permit quitting inside a
sentinel, bind inhibit-quit to nil. In most cases, the
right way to do this is with the macro with-local-quit.
See 退出.
If an error happens during execution of a sentinel, it is caught
automatically, so that it doesn’t stop the execution of whatever
programs was running when the sentinel was started. However, if
debug-on-error is non-nil, errors are not caught.
This makes it possible to use the Lisp debugger to debug the
sentinel. See Lisp 调试器. If an error is caught, Emacs pauses for
process-error-pause-time seconds so that the user sees the
error. See Creating an Asynchronous Process.
While a sentinel is running, the process sentinel is temporarily
set to nil so that the sentinel won’t run recursively.
For this reason it is not possible for a sentinel to specify
a new sentinel.
Note that Emacs automatically saves and restores the match data while executing sentinels. See The Match Data.
This function associates sentinel with process. If
sentinel is nil, then the process will have the default
sentinel, which inserts a message in the process’s buffer when the
process status changes.
Changes in process sentinels take effect immediately—if the sentinel is slated to be run but has not been called yet, and you specify a new sentinel, the eventual call to the sentinel will use the new one.
(defun msg-me (process event)
(princ
(format "Process: %s had the event '%s'" process event)))
(set-process-sentinel (get-process "shell") 'msg-me)
⇒ msg-me
(kill-process (get-process "shell"))
⊣ Process: #<process shell> had the event 'killed'
⇒ #<process shell>
This function returns the sentinel of process.
In case a process status changes need to be passed to several sentinels, you
can use add-function to combine an existing sentinel with a new one.
See 为 Emacs Lisp 函数添加建议.
While a sentinel or filter function is running, this function returns
non-nil if Emacs was waiting for keyboard input from the user at
the time the sentinel or filter function was called, or nil if it
was not.
When Emacs exits, it terminates all its subprocesses. For
subprocesses that run a program, it sends them the SIGHUP
signal; connections are simply closed. Because subprocesses may be
doing valuable work, Emacs normally asks the user to confirm that it
is ok to terminate them. Each process has a query flag, which, if
non-nil, says that Emacs should ask for confirmation before
exiting and thus killing that process. The default for the query flag
is t, meaning do query.
This returns the query flag of process.
This function sets the query flag of process to flag. It returns flag.
Here is an example of using set-process-query-on-exit-flag on a
shell process to avoid querying:
(set-process-query-on-exit-flag (get-process "shell") nil)
⇒ nil
If this user option is set to t (the default), then Emacs asks
for confirmation before killing processes on exit. If it is
nil, Emacs kills processes without confirmation, i.e., the
query flag of all processes is ignored.
In addition to accessing and manipulating processes that are subprocesses of the current Emacs session, Emacs Lisp programs can also access other processes. We call these system processes, to distinguish them from Emacs subprocesses.
Emacs provides several primitives for accessing system processes.
Not all platforms support these primitives; on those which don’t,
these primitives return nil.
This function returns a list of all the processes running on the system. Each process is identified by its PID, a numerical process ID that is assigned by the OS and distinguishes the process from all the other processes running on the same machine at the same time.
If default-directory points to a remote host, processes of that
host are returned.
This function returns an alist of attributes for the process specified
by its process ID pid. Each association in the alist is of the
form (key . value), where key designates the
attribute and value is the value of that attribute. The various
attribute keys that this function can return are listed below.
Not all platforms support all of these attributes; if an attribute is
not supported, its association will not appear in the returned alist.
If default-directory points to a remote host, pid is
regarded as process of that host.
euidThe effective user ID of the user who invoked the process. The
corresponding value is a number. If the process was invoked by
the same user who runs the current Emacs session, the value is
identical to what user-uid returns (see User Identification).
userUser name corresponding to the process’s effective user ID, a string.
egidThe group ID of the effective user ID, a number.
groupGroup name corresponding to the effective user’s group ID, a string.
commThe name of the command that runs in the process. This is a string that usually specifies the name of the executable file of the process, without the leading directories. However, some special system processes can report strings that do not correspond to an executable file of a program.
stateThe state code of the process. This is a short string that encodes the scheduling state of the process. Here’s a list of the most frequently seen codes:
"D"uninterruptible sleep (usually I/O)
"R"running
"S"interruptible sleep (waiting for some event)
"T"stopped, e.g., by a job control signal
"Z"zombie: a process that terminated, but was not reaped by its parent
For the full list of the possible states, see the manual page of the
ps command.
ppidThe process ID of the parent process, a number.
pgrpThe process group ID of the process, a number.
sessThe session ID of the process. This is a number that is the process ID of the process’s session leader.
ttnameA string that is the name of the process’s controlling terminal. On Unix and GNU systems, this is normally the file name of the corresponding terminal device, such as /dev/pts65.
tpgidThe numerical process group ID of the foreground process group that uses the process’s terminal.
minfltThe number of minor page faults caused by the process since its beginning. (Minor page faults are those that don’t involve reading from disk.)
majfltThe number of major page faults caused by the process since its beginning. (Major page faults require a disk to be read, and are thus more expensive than minor page faults.)
cminfltcmajfltLike minflt and majflt, but include the number of page
faults for all the child processes of the given process.
utimeTime spent by the process in the user context, for running the application’s code. The corresponding value is a Lisp timestamp (see Time of Day).
stimeTime spent by the process in the system (kernel) context, for processing system calls. The corresponding value is a Lisp timestamp.
timeThe sum of utime and stime. The corresponding
value is a Lisp timestamp.
cutimecstimectimeLike utime, stime, and time, but include the
times of all the child processes of the given process.
priThe numerical priority of the process.
niceThe nice value of the process, a number. (Processes with smaller nice values get scheduled more favorably.)
thcountThe number of threads in the process.
startThe time when the process was started, as a Lisp timestamp.
etimeThe time elapsed since the process started, as a Lisp timestamp.
vsizeThe virtual memory size of the process, measured in kilobytes.
rssThe size of the process’s resident set, the number of kilobytes occupied by the process in the machine’s physical memory.
pcpuThe percentage of the CPU time used by the process since it started. The corresponding value is a nonnegative floating-point number. Although in theory the number can exceed 100 on a multicore platform, it is usually less than 100 because Emacs is typically single-threaded.
pmemThe percentage of the total physical memory installed on the machine used by the process’s resident set. The value is a floating-point number between 0 and 100.
argsThe command-line with which the process was invoked. This is a string
in which individual command-line arguments are separated by blanks;
whitespace characters that are embedded in the arguments are quoted as
appropriate for the system’s shell: escaped by backslash characters on
GNU and Unix, and enclosed in double quote characters on Windows.
Thus, this command-line string can be directly used in primitives such
as shell-command.
You can use a transaction queue to communicate with a subprocess
using transactions. First use tq-create to create a transaction
queue communicating with a specified process. Then you can call
tq-enqueue to send a transaction.
This function creates and returns a transaction queue communicating with process. The argument process should be a subprocess capable of sending and receiving streams of bytes. It may be a child process, or it may be a TCP connection to a server, possibly on another machine.
This function sends a transaction to queue queue. Specifying the queue has the effect of specifying the subprocess to talk to.
The argument question is the outgoing message that starts the transaction. The argument fn is the function to call when the corresponding answer comes back; it is called with two arguments: closure, and the answer received.
The argument regexp is a regular expression that should match
text at the end of the entire answer, but nothing before; that’s how
tq-enqueue determines where the answer ends.
If the argument delay-question is non-nil, delay sending
this question until the process has finished replying to any previous
questions. This produces more reliable results with some processes.
Shut down transaction queue queue, waiting for all pending transactions to complete, and then terminate the connection or child process.
Transaction queues are implemented by means of a filter function. See Process Filter Functions.
Emacs Lisp programs can open stream (TCP) and datagram (UDP) network
connections (see Datagrams) to other processes on the same machine
or other machines.
A network connection is handled by Lisp much like a subprocess, and is
represented by a process object. However, the process you are
communicating with is not a child of the Emacs process, has no
process ID, and you can’t kill it or send it signals. All you
can do is send and receive data. delete-process closes the
connection, but does not kill the program at the other end; that
program must decide what to do about closure of the connection.
Lisp programs can listen for connections by creating network servers. A network server is also represented by a kind of process object, but unlike a network connection, the network server never transfers data itself. When it receives a connection request, it creates a new network connection to represent the connection just made. (The network connection inherits certain information, including the process plist, from the server.) The network server then goes back to listening for more connection requests.
Network connections and servers are created by calling
make-network-process with an argument list consisting of
keyword/argument pairs, for example :server t to create a
server process, or :type 'datagram to create a datagram
connection. See Low-Level Network Access, for details. You can also use
the open-network-stream function described below.
To distinguish the different types of processes, the
process-type function returns the symbol network for a
network connection or server, serial for a serial port
connection, pipe for a pipe connection, or real for a
real subprocess.
The process-status function returns open,
closed, connect, stop, or failed for
network connections. For a network server, the status is always
listen. Except for stop, none of those values is
possible for a real subprocess. See Process Information.
You can stop and resume operation of a network process by calling
stop-process and continue-process. For a server
process, being stopped means not accepting new connections. (Up to 5
connection requests will be queued for when you resume the server; you
can increase this limit, unless it is imposed by the operating
system—see the :server keyword of make-network-process,
make-network-process.) For a network stream connection, being
stopped means not processing input (any arriving input waits until you
resume the connection). For a datagram connection, some number of
packets may be queued but input may be lost. You can use the function
process-command to determine whether a network connection or
server is stopped; a non-nil value means yes.
Emacs can create encrypted network connections, using the built-in
support for the GnuTLS Transport Layer Security Library; see
the GnuTLS project page.
If your Emacs was compiled with GnuTLS support, the function
gnutls-available-p is defined and returns non-nil. For
more details, see Overview in The Emacs-GnuTLS manual.
The open-network-stream function can transparently handle the
details of creating encrypted connections for you, using whatever
support is available.
This function opens a TCP connection, with optional encryption, and returns a process object that represents the connection.
The name argument specifies the name for the process object. It is modified as necessary to make it unique.
The buffer argument is the buffer to associate with the
connection. Output from the connection is inserted in the buffer,
unless you specify your own filter function to handle the output. If
buffer is nil, it means that the connection is not
associated with any buffer.
The arguments host and service specify where to connect to;
host is the host name (a string), and service is the name of
a defined network service (a string) or a port number (an integer like
80 or an integer string like "80").
The remaining arguments parameters are keyword/argument pairs that are mainly relevant to encrypted connections:
:nowait booleanIf non-nil, try to make an asynchronous connection.
:noquery query-flagInitialize the process query flag to query-flag. See Querying Before Exit.
:coding codingUse this to set the coding systems used by the network process, in
preference to binding coding-system-for-read or
coding-system-for-write. See make-network-process, for
details.
:type typeThe type of connection. Options are:
plainAn ordinary, unencrypted connection.
tlssslA TLS (Transport Layer Security) connection.
nilnetworkStart with a plain connection, and if parameters ‘:success’ and ‘:capability-command’ are supplied, try to upgrade to an encrypted connection via STARTTLS. If that fails, retain the unencrypted connection.
starttlsAs for nil, but if STARTTLS fails, drop the connection.
shellA shell connection.
:always-query-capabilities booleanIf non-nil, always ask for the server’s capabilities, even when
doing a ‘plain’ connection.
:capability-command capability-commandCommand to query the host capabilities. This can either be a string (which will then be sent verbatim to the server) or a function (called with a single parameter: the “greeting” from the server when connecting) that should return a string.
:end-of-command regexp:end-of-capability regexpRegular expression matching the end of a command, or the end of the command capability-command. The latter defaults to the former.
:starttls-function functionFunction of one argument (the response to capability-command),
which returns either nil or the command to activate
STARTTLS, if supported.
:success regexpRegular expression matching a successful STARTTLS negotiation.
:use-starttls-if-possible booleanIf non-nil, do opportunistic STARTTLS upgrades even if Emacs
doesn’t have built-in TLS support.
:warn-unless-encrypted booleanIf non-nil, warn the user if the final connection type is not
encrypted. This is useful for protocols like IMAP and the
like, where most users would expect the network traffic to be encrypted.
This may be due to STARTTLS upgrade failure, specifying
:return-list non-nil allows you to capture any error
encountered.
:client-certificate list-or-t ¶Either a list of the form (key-file cert-file),
naming the certificate key file and certificate file itself, or
t, meaning to query auth-source for this information
(see auth-source in Emacs auth-source
Library). Only used for TLS or STARTTLS. To
enable automatic queries of auth-source when
:client-certificate is not specified customize
network-stream-use-client-certificates to t.
:return-list cons-or-nilThe return value of this function. If omitted or nil, return a
process object. Otherwise, a cons of the form
(process-object . plist), where plist can
include the following keywords:
:greeting string-or-nilIf non-nil, the greeting string returned by the host.
:capabilities string-or-nilIf non-nil, the host’s capability string.
:type symbolThe connection type: ‘plain’ or ‘tls’.
:error symbolA string describing any error encountered when performing STARTTLS upgrade.
:shell-command string-or-nilIf the connection type is shell, this parameter will be
interpreted as a format-spec string (see 自定义格式字符串)
that will be executed to make the connection. The specs available are
‘%s’ for the host name and ‘%p’ for the port number. For
instance, if you want to first ssh to ‘gateway’ before making a
plain connection, then this parameter’s value could be something like
‘ssh gateway nc %s %p’.
You create a server by calling make-network-process
(see make-network-process) with :server t. The server will
listen for connection requests from clients. When it accepts a client
connection request, that creates a new network connection, itself a
process object, with the following parameters:
The server’s process buffer value is never used directly, but the log function can retrieve it and use it to log connections by inserting text there.
process-contact
keywords :host, :service, :remote.
A datagram connection communicates with individual packets rather
than streams of data. Each call to process-send sends one
datagram packet (see Sending Input to Processes), and each datagram
received results in one call to the filter function.
The datagram connection doesn’t have to talk with the same remote
peer all the time. It has a remote peer address which specifies
where to send datagrams to. Each time an incoming datagram is passed
to the filter function, the peer address is set to the address that
datagram came from; that way, if the filter function sends a datagram,
it will go back to that place. You can specify the remote peer
address when you create the datagram connection using the
:remote keyword. You can change it later on by calling
set-process-datagram-address.
If process is a datagram connection or server, this function returns its remote peer address.
If process is a datagram connection or server, this function sets its remote peer address to address.
You can also create network connections by operating at a lower
level than that of open-network-stream, using
make-network-process.
make-network-process ¶The basic function for creating network connections and network
servers is make-network-process. It can do either of those
jobs, depending on the arguments you give it.
This function creates a network connection or server and returns the
process object that represents it. The arguments args are a
list of keyword/argument pairs. Omitting a keyword is always
equivalent to specifying it with value nil, except for
:coding, :filter-multibyte, and :reuseaddr. Here
are the meaningful keywords (those corresponding to network options
are listed in the following section):
:name nameUse the string name as the process name. It is modified if necessary to make it unique.
:type typeSpecify the communication type. A value of nil specifies a
stream connection (the default); datagram specifies a datagram
connection; seqpacket specifies a sequenced packet stream
connection. Both connections and servers can be of these types.
:server server-flagIf server-flag is non-nil, create a server. Otherwise,
create a connection. For a stream type server, server-flag may
be an integer, which then specifies the length of the queue of pending
connections to the server. The default queue length is 5.
:host hostSpecify the host to connect to. host should be a host name or
Internet address, as a string, or the symbol local to specify
the local host. If you specify host for a server, it must
specify a valid address for the local host, and only clients
connecting to that address will be accepted. When using local,
by default IPv4 will be used, specify a family of ipv6 to
override this. To listen on all interfaces, specify an address of
‘"0.0.0.0"’ for IPv4 or ‘"::"’ for IPv6. Note that on some
operating systems, listening on ‘"::"’ will also listen on IPv4,
so attempting to then listen separately on IPv4 will result in
EADDRINUSE errors (‘"Address already in use"’).
:service serviceservice specifies a port number to connect to; or, for a server,
the port number to listen on. It should be a service name like
‘"https"’ that translates to a port number, or an integer like ‘443’
or an integer string like ‘"443"’ that specifies the port number
directly. For a server, it can also be t, which means to let
the system select an unused port number.
:family familyfamily specifies the address (and protocol) family for
communication. nil means determine the proper address family
automatically for the given host and service.
local specifies a Unix socket, in which case host is
ignored. ipv4 and ipv6 specify to use IPv4 and IPv6,
respectively.
:use-external-socket use-external-socketIf use-external-socket is non-nil use any sockets passed
to Emacs on invocation instead of allocating one. This is used by the
Emacs server code to allow on-demand socket activation. If Emacs
wasn’t passed a socket, this option is silently ignored.
:local local-addressFor a server process, local-address is the address to listen on. It overrides family, host and service, so you might as well not specify them.
:remote remote-addressFor a connection, remote-address is the address to connect to. It overrides family, host and service, so you might as well not specify them.
For a datagram server, remote-address specifies the initial setting of the remote datagram address.
The format of local-address or remote-address depends on the address family:
[a b c d p] corresponding to
numeric IPv4 address a.b.c.d and port number
p.
[a b c d e f
g h p] corresponding to numeric IPv6 address
a:b:c:d:e:f:g:h and
port number p.
(f . av), where f is the family number and
av is a vector specifying the socket address using one element
per address data byte. Do not rely on this format in portable code,
as it may depend on implementation defined constants, data sizes, and
data structure alignment.
:nowait boolIf bool is non-nil for a stream connection, return
without waiting for the connection to complete. When the connection
succeeds or fails, Emacs will call the sentinel function, with a
second argument matching "open" (if successful) or
"failed". The default is to block, so that
make-network-process does not return until the connection has
succeeded or failed.
If you’re setting up an asynchronous TLS connection, you have to also
provide the :tls-parameters parameter (see below).
Depending on the capabilities of Emacs, how asynchronous
:nowait is may vary. The three elements that may (or may not)
be done asynchronously are domain name resolution, socket setup, and
(for TLS connections) TLS negotiation.
Many functions that interact with process objects, (for instance,
process-datagram-address) rely on them at least having a socket
before they can return a useful value. These functions will block
until the socket has achieved the desired status. The recommended way
of interacting with asynchronous sockets is to place a sentinel on the
process, and not try to interact with it before it has changed status
to ‘"run"’. That way, none of these functions will block.
:tls-parametersWhen opening a TLS connection, this should be where the first element
is the TLS type (which should either be gnutls-x509pki or
gnutls-anon, and the remaining elements should form a keyword
list acceptable for gnutls-boot. (This keyword list can be
obtained from the gnutls-boot-parameters function.) The TLS
connection will then be negotiated after completing the connection to
the host.
:stop stoppedIf stopped is non-nil, start the network connection or
server in the stopped state.
:buffer bufferUse buffer as the process buffer.
:coding codingUse coding as the coding system for this process. To specify
different coding systems for decoding data from the connection and for
encoding data sent to it, specify (decoding .
encoding) for coding.
If you don’t specify this keyword at all, the default is to determine the coding systems from the data.
:noquery query-flagInitialize the process query flag to query-flag. See Querying Before Exit.
:filter filterInitialize the process filter to filter.
:filter-multibyte multibyteIf multibyte is non-nil, strings given to the process
filter are multibyte, otherwise they are unibyte. The default is t.
:sentinel sentinelInitialize the process sentinel to sentinel.
:log logInitialize the log function of a server process to log. The log function is called each time the server accepts a network connection from a client. The arguments passed to the log function are server, connection, and message; where server is the server process, connection is the new process for the connection, and message is a string describing what has happened.
:plist plistInitialize the process plist to plist.
The original argument list, modified with the actual connection
information, is available via the process-contact function.
The following network options can be specified when you create a
network process. Except for :reuseaddr, you can also set or
modify these options later, using set-network-process-option.
For a server process, the options specified with
make-network-process are not inherited by the client
connections, so you will need to set the necessary options for each
child connection as it is created.
:bindtodevice device-nameIf device-name is a non-empty string identifying a network
interface name (see network-interface-list), only handle
packets received on that interface. If device-name is nil
(the default), handle packets received on any interface.
Using this option may require special privileges on some systems.
:broadcast broadcast-flagIf broadcast-flag is non-nil for a datagram process, the
process will receive datagram packet sent to a broadcast address, and
be able to send packets to a broadcast address. This is ignored for a stream
connection.
:dontroute dontroute-flagIf dontroute-flag is non-nil, the process can only send
to hosts on the same network as the local host.
:keepalive keepalive-flagIf keepalive-flag is non-nil for a stream connection,
enable exchange of low-level keep-alive messages.
:linger linger-argIf linger-arg is non-nil, wait for successful
transmission of all queued packets on the connection before it is
deleted (see delete-process). If linger-arg is an
integer, it specifies the maximum time in seconds to wait for queued
packets to be sent before closing the connection. The default is
nil, which means to discard unsent queued packets when the
process is deleted.
:oobinline oobinline-flagIf oobinline-flag is non-nil for a stream connection,
receive out-of-band data in the normal data stream. Otherwise, ignore
out-of-band data.
:priority prioritySet the priority for packets sent on this connection to the integer priority. The interpretation of this number is protocol specific; such as setting the TOS (type of service) field on IP packets sent on this connection. It may also have system dependent effects, such as selecting a specific output queue on the network interface.
:reuseaddr reuseaddr-flagIf reuseaddr-flag is non-nil (the default) for a stream
server process, allow this server to reuse a specific port number (see
:service), unless another process on this host is already
listening on that port. If reuseaddr-flag is nil, there
may be a period of time after the last use of that port (by any
process on the host) where it is not possible to make a new server on
that port.
This function sets or modifies a network option for network process
process. The accepted options and values are as for
make-network-process. If no-error is non-nil,
this function returns nil instead of signaling an error if
option is not a supported option. If the function successfully
completes, it returns t.
The current setting of an option is available via the
process-contact function.
To test for the availability of a given network feature, use
featurep like this:
(featurep 'make-network-process '(keyword value))
The result of this form is t if it works to specify
keyword with value value in make-network-process.
Here are some of the keyword—value pairs you can test in
this way.
(:nowait t)Non-nil if non-blocking connect is supported.
(:type datagram)Non-nil if datagrams are supported.
(:family local)Non-nil if local (a.k.a. “UNIX domain”) sockets are supported.
(:family ipv6)Non-nil if IPv6 is supported.
(:service t)Non-nil if the system can select the port for a server.
To test for the availability of a given network option, use
featurep like this:
(featurep 'make-network-process 'keyword)
The accepted keyword values are :bindtodevice, etc.
For the complete list, see Network Options. This form returns
non-nil if that particular network option is supported by
make-network-process (or set-network-process-option).
These additional functions are useful for creating and operating on network connections. Note that they are supported only on some systems.
This function returns a list describing the network interfaces of the
machine you are using. The value is an alist whose elements have the
form (ifname . address). ifname is a string
naming the interface, address has the same form as the
local-address and remote-address arguments to
make-network-process, i.e. a vector of integers. By default
both IPv4 and IPv6 addresses are returned if possible.
Optional argument full non-nil means to instead return a
list of one or more elements of the form (ifname addr bcast netmask). ifname is a non-unique
string naming the interface. addr, bcast, and
netmask are vectors of integers detailing the IP address,
broadcast address, and network mask.
Optional argument family specified as symbol ipv4 or
ipv6 restricts the returned information to IPv4 and IPv6
addresses respectively, independently of the value of full.
Specifying ipv6 when IPv6 support is not available will result
in an error being signaled.
Some examples:
(network-interface-list) ⇒
(("vmnet8" .
[172 16 76 1 0])
("vmnet1" .
[172 16 206 1 0])
("lo0" .
[65152 0 0 0 0 0 0 1 0])
("lo0" .
[0 0 0 0 0 0 0 1 0])
("lo0" .
[127 0 0 1 0]))
(network-interface-list t) ⇒
(("vmnet8"
[172 16 76 1 0]
[172 16 76 255 0]
[255 255 255 0 0])
("vmnet1"
[172 16 206 1 0]
[172 16 206 255 0]
[255 255 255 0 0])
("lo0"
[65152 0 0 0 0 0 0 1 0]
[65152 0 0 0 65535 65535 65535 65535 0]
[65535 65535 65535 65535 0 0 0 0 0])
("lo0"
[0 0 0 0 0 0 0 1 0]
[0 0 0 0 0 0 0 1 0]
[65535 65535 65535 65535 65535 65535 65535 65535 0])
("lo0"
[127 0 0 1 0]
[127 255 255 255 0]
[255 0 0 0 0]))
This function returns information about the network interface named
ifname. The value is a list of the form
(addr bcast netmask hwaddr flags).
The Internet protocol address.
The broadcast address.
The network mask.
The layer 2 address (Ethernet MAC address, for instance).
The current flags of the interface.
Note that this function returns only IPv4 information.
This function converts the Lisp representation of a network address to a string.
A five-element vector [a b c d p]
represents an IPv4 address a.b.c.d and port
number p. format-network-address converts that to the
string "a.b.c.d:p".
A nine-element vector [a b c d e
f g h p] represents an IPv6 address along
with a port number. format-network-address converts that to
the string
"[a:b:c:d:e:f:g:h]:p".
If the vector does not include the port number, p, or if
omit-port is non-nil, the result does not include the
:p suffix.
This function perform hostname lookups on name, which is
expected to be an ASCII-only string, otherwise it signals an error. Call
puny-encode-domain on name first if you wish to lookup
internationalized hostnames.
If successful, this function returns a list of Lisp representations of network
addresses (see make-network-process, for a description of the
format), otherwise return nil. In the latter case, it also logs
an error message hopefully explaining what went wrong.
By default, this function attempts both IPv4 and IPv6 lookups. The
optional argument family controls this behavior, specifying the
symbol ipv4 or ipv6 restricts lookups to IPv4 and IPv6
respectively.
If optional argument hints is numeric, the function
treats the name as a numerical IP address (and does not perform DNS
lookups). This can be used to check whether a string is a valid
numerical representation of an IP address, or to convert a numerical
string to its canonical representation. e.g.
(network-lookup-address-info "127.1" 'ipv4 'numeric)
⇒ ([127 0 0 1 0])
(network-lookup-address-info "::1" nil 'numeric)
⇒ ([0 0 0 0 0 0 0 1 0])
Be warned that there are some surprising valid forms, especially for IPv4, e.g ‘0xe3010203’ and ‘0343.1.2.3’ are both valid, as are ‘0’ and ‘1’ (but they are invalid for IPv6).
Emacs can communicate with serial ports. For interactive use,
M-x serial-term opens a terminal window. In a Lisp program,
make-serial-process creates a process object.
The serial port can be configured at run-time, without having to
close and re-open it. The function serial-process-configure
lets you change the speed, bytesize, and other parameters. In a
terminal window created by serial-term, you can click on the
mode line for configuration.
A serial connection is represented by a process object, which can be
used in a similar way to a subprocess or network process. You can send and
receive data, and configure the serial port. A serial process object
has no process ID, however, and you can’t send signals to it, and the
status codes are different from other types of processes.
delete-process on the process object or kill-buffer on
the process buffer close the connection, but this does not affect the
device connected to the serial port.
The function process-type returns the symbol serial
for a process object representing a serial port connection.
Serial ports are available on GNU/Linux, Unix, and MS Windows systems.
Start a terminal-emulator for a serial port in a new buffer. port is the name of the serial port to connect to. For example, this could be /dev/ttyS0 on Unix. On MS Windows, this could be COM1, or \\.\COM10 (double the backslashes in Lisp strings).
speed is the speed of the serial port in bits per second. 9600
is a common value. The buffer is in Term mode; see Term Mode in The GNU Emacs Manual, for the commands to use in that buffer.
You can change the speed and the configuration in the mode line menu.
If line-mode is non-nil, term-line-mode is used;
otherwise term-raw-mode is used.
This function creates a process and a buffer. Arguments are specified as keyword/argument pairs. Here’s the list of the meaningful keywords, with the first two (port and speed) being mandatory:
:port portThis is the name of the serial port. On Unix and GNU systems, this is a file name such as /dev/ttyS0. On Windows, this could be COM1, or \\.\COM10 for ports higher than COM9 (double the backslashes in Lisp strings).
:speed speedThe speed of the serial port in bits per second. This function calls
serial-process-configure to handle the speed; see the
following documentation of that function for more details.
:name nameThe name of the process. If name is not given, port will serve as the process name as well.
:buffer bufferThe buffer to associate with the process. The value can be either a
buffer or a string that names a buffer. Process output goes at the
end of that buffer, unless you specify an output stream or filter
function to handle the output. If buffer is not given, the
process buffer’s name is taken from the value of the :name
keyword.
:coding codingIf coding is a symbol, it specifies the coding system used for
both reading and writing for this process. If coding is a cons
(decoding . encoding), decoding is used for
reading, and encoding is used for writing. If not specified,
the default is to determine the coding systems from the data itself.
:noquery query-flagInitialize the process query flag to query-flag. See Querying Before Exit. The flags defaults to nil if unspecified.
:stop boolStart process in the stopped state if bool is
non-nil. In the stopped state, a serial process does not
accept incoming data, but you can send outgoing data. The stopped
state is cleared by continue-process and set by
stop-process.
:filter filterInstall filter as the process filter.
:sentinel sentinelInstall sentinel as the process sentinel.
:plist plistInstall plist as the initial plist of the process.
:bytesize:parity:stopbits:flowcontrolThese are handled by serial-process-configure, which is called
by make-serial-process.
The original argument list, possibly modified by later configuration,
is available via the function process-contact.
Here is an example:
(make-serial-process :port "/dev/ttyS0" :speed 9600)
This function configures a serial port connection. Arguments are
specified as keyword/argument pairs. Attributes that are not given
are re-initialized from the process’s current configuration (available
via the function process-contact), or set to reasonable default
values. The following arguments are defined:
:process process:name name:buffer buffer:port portAny of these arguments can be given to identify the process that is to be configured. If none of these arguments is given, the current buffer’s process is used.
:speed speedThe speed of the serial port in bits per second, a.k.a. baud
rate. The value can be any number, but most serial ports work only
at a few defined values between 1200 and 115200, with 9600 being the
most common value. If speed is nil, the function ignores
all other arguments and does not configure the port. This may be
useful for special serial ports such as Bluetooth-to-serial converters,
which can only be configured through ‘AT’ commands sent through the
connection. The value of nil for speed is valid only for
connections that were already opened by a previous call to
make-serial-process or serial-term.
:bytesize bytesizeThe number of bits per byte, which can be 7 or 8. If bytesize
is not given or nil, it defaults to 8.
:parity parityThe value can be nil (don’t use parity), the symbol
odd (use odd parity), or the symbol even (use even
parity). If parity is not given, it defaults to no parity.
:stopbits stopbitsThe number of stopbits used to terminate a transmission
of each byte. stopbits can be 1 or 2. If stopbits is not
given or nil, it defaults to 1.
:flowcontrol flowcontrolThe type of flow control to use for this connection, which is either
nil (don’t use flow control), the symbol hw (use RTS/CTS
hardware flow control), or the symbol sw (use XON/XOFF software
flow control). If flowcontrol is not given, it defaults to no
flow control.
Internally, make-serial-process calls
serial-process-configure for the initial configuration of the
serial port.
This section describes how to pack and unpack arrays of bytes,
usually for binary network protocols. These functions convert byte arrays
to alists, and vice versa. The byte array can be represented as a
unibyte string or as a vector of integers, while the alist associates
symbols either with fixed-size objects or with recursive sub-alists.
To use the functions referred to in this section, load the
bindat library.
Conversion from byte arrays to nested alists is also known as deserializing or unpacking, while going in the opposite direction is also known as serializing or packing.
To control unpacking and packing, you write a data layout
specification, also called a Bindat type expression. This can
be a base type or a composite type made of several fields,
where the specification controls the length of each field to be
processed, and how to pack or unpack it. We normally keep bindat type
values in variables whose names end in -bindat-spec; that kind
of name is automatically recognized as risky (see 文件局部变量).
Creates a Bindat type value object according to the Bindat type expression type.
A field’s type describes the size (in bytes) of the object
that the field represents and, in the case of multibyte fields, how
the bytes are ordered within the field. The two possible orderings
are big endian (also known as “network byte ordering”) and
little endian. For instance, the number #x23cd (decimal
9165) in big endian would be the two bytes #x23 #xcd;
and in little endian, #xcd #x23. Here are the possible
type values:
u8byteUnsigned byte, with length 1.
uint bitlen &optional leUnsigned integer in network byte order (big-endian), with bitlen bits.
bitlen has to be a multiple of 8.
If le is non-nil, then use little-endian byte order.
sint bitlen leSigned integer in network byte order (big-endian), with bitlen bits.
bitlen has to be a multiple of 8.
If le is non-nil, then use little-endian byte order.
str lenUnibyte string (see Text Representations) of length len bytes.
When packing, the first len bytes of the input string are copied
to the packed output. If the input string is shorter than len,
the remaining bytes will be null (zero) unless a pre-allocated string
was provided to bindat-pack, in which case the remaining bytes
are left unmodified. If the input string is multibyte with only ASCII
and eight-bit characters, it is converted to unibyte before it
is packed; other multibyte strings signal an error. When unpacking,
any null bytes in the packed input string will appear in the unpacked
output.
strz &optional lenIf len is not provided, this is a variable-length
null-terminated unibyte string (see Text Representations). When
packing into strz, the entire input string is copied to the
packed output followed by a null (zero) byte. (If pre-allocated
string is provided for packing into strz, that pre-allocated
string should have enough space for the additional null byte appended
to the output string contents, see Functions to Unpack and Pack Bytes). The length
of the packed output is the length of the input string plus one (for
the null terminator). The input string must not contain any null
bytes. If the input string is multibyte with only ASCII and
eight-bit characters, it is converted to unibyte before it is
packed; other multibyte strings signal an error. When unpacking a
strz, the resulting output string will contain all bytes up to
(but excluding) the null byte that terminated the input string.
If len is provided, strz behaves the same as str,
but with a couple of differences:
Caution: The packed output will not be null-terminated unless the input string is shorter than len bytes or it contains a null byte within the first len bytes.
vec len [type]Vector of len elements. The type of the elements is given by type, defaulting to bytes. The type can be any Bindat type expression.
repeat len [type]Like vec, but it unpacks to and packs from lists, whereas
vec unpacks to vectors.
bits lenList of bits that are set to 1 in len bytes. The bytes are
taken in big-endian order, and the bits are numbered starting with
8 * len − 1 and ending with zero. For example:
bits 2 unpacks #x28 #x1c to (2 3 4 11 13)
and #x1c #x28 to (3 5 10 11 12).
fill lenlen bytes used as a mere filler. In packing, these bytes are
left unchanged, which normally means they remain zero.
When unpacking, this just returns nil.
align lenSame as fill except the number of bytes is that needed to skip
to the next multiple of len bytes.
type expThis lets you refer to a type indirectly: exp is a Lisp expression which should return a Bindat type value.
unit expThis is a trivial type which uses up 0 bits of space. exp describes the value returned when we try to “unpack” such a field.
struct fields...Composite type made of several fields. Every field is of the form
(name type) where type can be any Bindat
type expression. name can be _ when the field’s value
does not deserve to be named, as is often the case for align
and fill fields.
When the context makes it clear that this is a Bindat type expression,
the symbol struct can be omitted.
In the types above, len and bitlen are given as an integer specifying the number of bytes (or bits) in the field. When the length of a field is not fixed, it typically depends on the value of preceding fields. For this reason, the length len does not have to be a constant but can be any Lisp expression and it can refer to the value of previous fields via their name.
For example, the specification of a data layout where a leading byte gives the size of a subsequent vector of 16 bit integers could be:
(bindat-type (len u8) (payload vec (1+ len) uint 16))
In the following documentation, type refers to a Bindat type
value as returned from bindat-type, raw to a byte
array, and struct to an alist representing unpacked field data.
This function unpacks data from the unibyte string or byte
array raw
according to type. Normally, this starts unpacking at the
beginning of the byte array, but if idx is non-nil, it
specifies a zero-based starting position to use instead.
The value is an alist or nested alist in which each element describes one unpacked field.
This function selects a field’s data from the nested alist
struct. Usually struct was returned by
bindat-unpack. If name corresponds to just one argument,
that means to extract a top-level field value. Multiple name
arguments specify repeated lookup of sub-structures. An integer
name acts as an array index.
For example, (bindat-get-field struct a b 2 c) means
to find field c in the third element of subfield b of
field a. (This corresponds to struct.a.b[2].c in
the C programming language syntax.)
Although packing and unpacking operations change the organization of data (in memory), they preserve the data’s total length, which is the sum of all the fields’ lengths, in bytes. This value is not generally inherent in either the specification or alist alone; instead, both pieces of information contribute to its calculation. Likewise, the length of a string or array being unpacked may be longer than the data’s total length as described by the specification.
This function returns the total length of the data in struct, according to type.
This function returns a byte array packed according to type from
the data in the alist struct. It normally creates and fills a
new byte array starting at the beginning. However, if raw
is non-nil, it specifies a pre-allocated unibyte string or vector to
pack into. If idx is non-nil, it specifies the starting
offset for packing into raw.
When pre-allocating, you should make sure (length raw)
meets or exceeds the total length to avoid an out-of-range error.
Convert the Internet address vector ip to a string in the usual dotted notation.
(bindat-ip-to-string [127 0 0 1])
⇒ "127.0.0.1"
Bindat type expressions are not limited to the types described earlier. They can also be arbitrary Lisp forms returning Bindat type expressions. For example, the type below describes data which can either contain a 24-bit error code or a vector of bytes:
(bindat-type (len u8) (payload . (if (zerop len) (uint 24) (vec (1- len)))))
Furthermore, while composite types are normally unpacked to (and packed from) association lists, this can be changed via the use of the following special keyword arguments:
:unpack-val expWhen the list of fields ends with this keyword argument, then the value returned when unpacking is the value of exp instead of the standard alist. exp can refer to all the previous fields by their name.
:pack-val expIf a field’s type is followed by this keyword argument, then the value packed into this field is returned by exp instead of being extracted from the alist.
:pack-var nameIf the list of fields is preceded by this keyword argument, then all
the subsequent :pack-val arguments can refer to the overall
value to pack into this composite type via the variable named
name.
For example, one could describe a 16-bit signed integer as follows:
(defconst sint16-bindat-spec
(let* ((max (ash 1 15))
(wrap (+ max max)))
(bindat-type :pack-var v
(n uint 16 :pack-val (if (< v 0) (+ v wrap) v))
:unpack-val (if (>= n max) (- n wrap) n))))
Which would then behave as follows:
(bindat-pack sint16-bindat-spec -8)
⇒ "\377\370"
(bindat-unpack sint16-bindat-spec "\300\100")
⇒ -16320
Finally, you can define new Bindat type forms to use in Bindat type
expressions with bindat-defmacro:
Define a new Bindat type expression named name and taking
arguments args. Its behavior follows that of defmacro,
which the important difference that the new forms can only be used
within Bindat type expressions.
This chapter describes a number of features related to the display that Emacs presents to the user.
display PropertyThe function redraw-frame clears and redisplays the entire
contents of a given frame (see Frames). This is useful if the
screen is corrupted.
This function clears and redisplays frame frame. If frame
is omitted or nil, it redraws the selected frame.
Even more powerful is redraw-display:
This function clears and redisplays all visible frames.
In Emacs, processing user input takes priority over redisplay. If you call these functions when input is available, they don’t redisplay immediately, but the requested redisplay does happen eventually—after all the input has been processed.
On text terminals, suspending and resuming Emacs normally also refreshes the screen. Some terminal emulators record separate contents for display-oriented programs such as Emacs and for ordinary sequential display. If you are using such a terminal, you might want to inhibit the redisplay on resumption.
This variable controls whether Emacs redraws the entire screen after it
has been suspended and resumed. Non-nil means there is no need
to redraw, nil means redrawing is needed. The default is nil.
Emacs normally tries to redisplay the screen whenever it waits for input. With the following function, you can request an immediate attempt to redisplay, in the middle of Lisp code, without actually waiting for input.
This function tries immediately to redisplay. The optional argument
force, if non-nil, forces the redisplay to be performed,
instead of being preempted if input is pending.
The function returns t if it actually tried to redisplay, and
nil otherwise. A value of t does not mean that
redisplay proceeded to completion; it could have been preempted by
newly arriving input.
Although redisplay tries immediately to redisplay, it does
not change how Emacs decides which parts of its frame(s) to redisplay.
By contrast, the following function adds certain windows to the
pending redisplay work (as if their contents had completely changed),
but does not immediately try to perform redisplay.
This function forces some or all windows to be updated the next time
Emacs does a redisplay. If object is a window, that window is
to be updated. If object is a buffer or buffer name, all
windows displaying that buffer are to be updated. If object is
nil (or omitted), all windows are to be updated.
This function does not do a redisplay immediately; Emacs does that as
it waits for input, or when the function redisplay is called.
A function run just before redisplay. It is called with one argument,
the set of windows to be redisplayed. The set can be nil,
meaning only the selected window, or t, meaning all the
windows.
This hook is run just before redisplay. It is called once in each
window that is about to be redisplayed, with current-buffer set
to the buffer displayed in that window.
When a line of text extends beyond the right edge of a window, Emacs can continue the line (make it wrap to the next screen line), or truncate the line (limit it to one screen line). The additional screen lines used to display a long text line are called continuation lines. Continuation is not the same as filling; continuation happens on the screen only, not in the buffer contents, and it breaks a line precisely at the right margin, not at a word boundary. See Filling.
On a graphical display, tiny arrow images in the window fringes
indicate truncated and continued lines (see Fringes). On a text
terminal, and on a graphical display when fringe-mode was
turned off, a ‘$’ in the rightmost column of the window indicates
truncation; a ‘\’ on the rightmost column indicates a line that
wraps. (The display table can specify alternate characters to use
for this; see Display Tables).
Since wrapping and truncation of text contradict each other, Emacs turns off line truncation when wrapping is requested, and vice versa.
If this buffer-local variable is non-nil, lines that extend
beyond the right edge of the window are truncated; otherwise, they are
continued. As a special exception, the variable
truncate-partial-width-windows takes precedence in
partial-width windows (i.e., windows that do not occupy the
entire frame width).
This variable controls line truncation in partial-width windows.
A partial-width window is one that does not occupy the entire frame
width (see Splitting Windows). If the value is nil, line
truncation is determined by the variable truncate-lines (see
above). If the value is an integer n, lines are truncated if
the partial-width window has fewer than n columns, regardless of
the value of truncate-lines; if the partial-width window has
n or more columns, line truncation is determined by
truncate-lines. For any other non-nil value, lines are
truncated in every partial-width window, regardless of the value of
truncate-lines.
When horizontal scrolling (see Horizontal Scrolling) is in use in a window, that forces truncation.
If this buffer-local variable is non-nil, it defines a
wrap prefix which Emacs displays at the start of every
continuation line. (If lines are truncated, wrap-prefix is
never used.) Its value may be a string or an image (see Other Display Specifications), or a stretch of whitespace such as specified by the
:width or :align-to display properties (see Specified Spaces). The value is interpreted in the same way as a display
text property, with one important difference: the horizontal position
specified by :align-to is measured from the visual beginning of
the screen line. See The display Property.
A wrap prefix may also be specified for regions of text, using the
wrap-prefix text or overlay property. This takes precedence
over the wrap-prefix variable. See Properties with Special Meanings.
If this buffer-local variable is non-nil, it defines a
line prefix which Emacs displays at the start of every
non-continuation line. Its value may be a string or an image
(see Other Display Specifications), or a stretch of whitespace such as
specified by the :width or :align-to display properties
(see Specified Spaces). The value is interpreted in the same way
as a display text property. See The display Property.
A line prefix may also be specified for regions of text using the
line-prefix text or overlay property. This takes precedence
over the line-prefix variable. See Properties with Special Meanings.
The echo area is used for displaying error messages
(see 错误), for messages made with the message primitive,
and for echoing keystrokes. It is not the same as the minibuffer,
despite the fact that the minibuffer appears (when active) in the same
place on the screen as the echo area. See The
Minibuffer in The GNU Emacs Manual.
Apart from the functions documented in this section, you can print
Lisp objects to the echo area by specifying t as the output
stream. See 输出流.
This section describes the standard functions for displaying messages in the echo area.
This function displays a message in the echo area.
format-string is a format string, and arguments are the
objects for its format specifications, like in the format-message
function (see 格式化字符串). The resulting formatted string
is displayed in the echo area; if it contains face text
properties, it is displayed with the specified faces (see Faces).
The string is also added to the *Messages* buffer, but without
text properties (see Logging Messages in *Messages*).
Typically grave accent and apostrophe in the format translate to
matching curved quotes, e.g., "Missing `%s'" might result in
"Missing ‘foo’". See 文本引用样式, for how to influence
or inhibit this translation.
In batch mode, the message is printed to the standard error stream, followed by a newline.
When inhibit-message is non-nil, no message will be displayed
in the echo area, it will only be logged to ‘*Messages*’.
If format-string is nil or the empty string,
message clears the echo area; if the echo area has been
expanded automatically, this brings it back to its normal size. If
the minibuffer is active, this brings the minibuffer contents back
onto the screen immediately.
(message "Reverting `%s'..." (buffer-name)) ⊣ Reverting ‘subr.el’... ⇒ "Reverting ‘subr.el’..."
---------- Echo Area ---------- Reverting ‘subr.el’... ---------- Echo Area ----------
To automatically display a message in the echo area or in a pop-buffer,
depending on its size, use display-message-or-buffer (see below).
Warning: If you want to use your own string as a message
verbatim, don’t just write (message string). If
string contains ‘%’, ‘`’, or ‘'’ it may be
reformatted, with undesirable results. Instead, use (message
"%s" string).
The following facilities allow users and Lisp programs to control how echo-area messages are displayed.
If this variable is non-nil, it should be a function of one
argument, the text of a message to display in the echo area. That
function will be called by message and related functions. If
the function returns nil, the message is displayed in the echo
area as usual. If the function returns a string, that string is
displayed in the echo area instead of the original message. If
the function returns any other non-nil value, that means the
message was already handled, so message will not display
anything in the echo area.
The default value calls set-minibuffer-message, described
below.
If this variable is non-nil, it should be a function of no
arguments; message and related functions call it when their
argument message is nil or the empty string, to clear the echo
area.
Usually this function is called when the next input event arrives
after displaying an echo-area message. The function is expected to
clear the message displayed by its counterpart function specified by
set-message-function, but doesn’t have to. If the function
wants the echo area to remain uncleared, it should return the symbol
dont-clear-message; any other value will result in the echo
area being cleared.
The default value is the function that clears the message displayed in an active minibuffer.
The value of this user option is a list of functions to be called for
handling display of echo-area messages. Each function is called with
one argument, the text of the message to display. If the function
returns a string, that string replaces the original message, and the
next function in the list is called with the new message text. If the
function returns nil, the next function in the list is called
with the same text; if the last function in the list returns
nil, the message text is displayed in the echo area. If the
function returns a non-nil value that is not a string, the
message is considered to be handled, and no further functions in the
list are called.
The three useful functions to be put in the list that is the value of this option are described below.
This function displays message in the echo-area when the
minibuffer is not active, and at the end of the minibuffer when the
minibuffer is active. However, if the text shown in the active
minibuffer has the minibuffer-message text property
(see Properties with Special Meanings) on some character, the message will be
displayed before the first character having that property.
This function is by default the only member of the list in
set-message-functions.
If an echo-area message matches any regexp in the list that is
the value of the user option inhibit-message-regexps, this
function suppresses the display of that message and returns a
non-nil value that is not a string. Thus, if this function is
in the list set-message-functions, the rest of the functions in
the list will not be called when message matches the regexps in
inhibit-message-regexps. To ensure a matching message
will never be displayed, make this function be the first element of
the list in set-message-functions.
This function accumulates several echo-area messages emitted one after
another, and returns them as a single string in which individual
messages are separated by newlines. Up to multi-message-max
recent messages can be accumulated. The accumulated messages are
discarded when more than multi-message-timeout seconds have
elapsed since the time the first message was emitted.
When this variable is non-nil, message and related functions
will not display any messages in the Echo Area. Echo-area messages
are still logged in the *Messages* buffer, though.
This construct displays a message in the echo area temporarily, during the execution of body. It displays message, executes body, then returns the value of the last body form while restoring the previous echo area contents.
This function displays a message like message, but may display it
in a dialog box instead of the echo area. If this function is called in
a command that was invoked using the mouse—more precisely, if
last-nonmenu-event (see 来自命令循环的信息) is either
nil or a list—then it uses a dialog box or pop-up menu to
display the message. Otherwise, it uses the echo area. (This is the
same criterion that y-or-n-p uses to make a similar decision; see
Yes-or-No 查询.)
You can force use of the mouse or of the echo area by binding
last-nonmenu-event to a suitable value around the call.
This function displays a message like message, but uses a dialog
box (or a pop-up menu) whenever that is possible. If it is impossible
to use a dialog box or pop-up menu, because the terminal does not
support them, then message-box uses the echo area, like
message.
This function displays the message message, which may be either a
string or a buffer. If it is shorter than the maximum height of the
echo area, as defined by max-mini-window-height, it is displayed
in the echo area, using message. Otherwise,
display-buffer is used to show it in a pop-up buffer.
Returns either the string shown in the echo area, or when a pop-up buffer is used, the window used to display it.
If message is a string, then the optional argument buffer-name is the name of the buffer used to display it when a pop-up buffer is used, defaulting to *Message*. In the case where message is a string and displayed in the echo area, it is not specified whether the contents are inserted into the buffer anyway.
The optional arguments action and frame are as for
display-buffer, and only used if a buffer is displayed.
This function returns the message currently being displayed in the
echo area, or nil if there is none.
When an operation can take a while to finish, you should inform the user about the progress it makes. This way the user can estimate remaining time and clearly see that Emacs is busy working, not hung. A convenient way to do this is to use a progress reporter.
Here is a working example that does nothing useful:
(let ((progress-reporter
(make-progress-reporter "Collecting mana for Emacs..."
0 500)))
(dotimes (k 500)
(sit-for 0.01)
(progress-reporter-update progress-reporter k))
(progress-reporter-done progress-reporter))
This function creates and returns a progress reporter object, which you will use as an argument for the other functions listed below. The idea is to precompute as much data as possible to make progress reporting very fast.
When this progress reporter is subsequently used, it will display
message in the echo area, followed by progress percentage.
message is treated as a simple string. If you need it to depend
on a filename, for instance, use format-message before calling this
function.
The arguments min-value and max-value should be numbers
standing for the starting and final states of the operation. For
instance, an operation that scans a buffer should set these to the
results of point-min and point-max correspondingly.
max-value should be greater than min-value.
Alternatively, you can set min-value and max-value to
nil. In that case, the progress reporter does not report
process percentages; it instead displays a “spinner” that rotates a
notch each time you update the progress reporter.
If min-value and max-value are numbers, you can give the argument current-value a numerical value specifying the initial progress; if omitted, this defaults to min-value.
The remaining arguments control the rate of echo area updates. The progress reporter will wait for at least min-change more percents of the operation to be completed before printing next message; the default is one percent. min-time specifies the minimum time in seconds to pass between successive prints; the default is 0.2 seconds. (On some operating systems, the progress reporter may handle fractions of seconds with varying precision).
This function calls progress-reporter-update, so the first
message is printed immediately.
This function does the main work of reporting progress of your operation. It displays the message of reporter, followed by progress percentage determined by value. If percentage is zero, or close enough according to the min-change and min-time arguments, then it is omitted from the output.
reporter must be the result of a call to
make-progress-reporter. value specifies the current
state of your operation and must be between min-value and
max-value (inclusive) as passed to
make-progress-reporter. For instance, if you scan a buffer,
then value should be the result of a call to point.
Optional argument suffix is a string to be displayed after
reporter’s main message and progress text. If reporter is
a non-numerical reporter, then value should be nil, or a
string to use instead of suffix.
This function respects min-change and min-time as passed
to make-progress-reporter and so does not output new messages
on every invocation. It is thus very fast and normally you should not
try to reduce the number of calls to it: resulting overhead will most
likely negate your effort.
This function is similar to progress-reporter-update except
that it prints a message in the echo area unconditionally.
reporter, value, and suffix have the same meaning as for
progress-reporter-update. Optional new-message allows
you to change the message of the reporter. Since this function
always updates the echo area, such a change will be immediately
presented to the user.
This function should be called when the operation is finished. It prints the message of reporter followed by word ‘done’ in the echo area.
You should always call this function and not hope for
progress-reporter-update to print ‘100%’. Firstly, it may
never print it, there are many good reasons for this not to happen.
Secondly, ‘done’ is more explicit.
This is a convenience macro that works the same way as dotimes
does, but also reports loop progress using the functions described
above. It allows you to save some typing. The argument
reporter-or-message can be either a string or a progress
reporter object.
You can rewrite the example in the beginning of this subsection using this macro as follows:
(dotimes-with-progress-reporter
(k 500)
"Collecting some mana for Emacs..."
(sit-for 0.01))
Using a reporter object as the reporter-or-message argument is useful if you want to specify the optional arguments in make-progress-reporter. For instance, you can write the previous example as follows:
(dotimes-with-progress-reporter
(k 500)
(make-progress-reporter "Collecting some mana for Emacs..." 0 500 0 1 1.5)
(sit-for 0.01))
This is another convenience macro that works the same way as dolist
does, but also reports loop progress using the functions described
above. As in dotimes-with-progress-reporter,
reporter-or-message can be a progress reporter or a string.
You can rewrite the previous example with this macro as follows:
(dolist-with-progress-reporter
(k (number-sequence 0 500))
"Collecting some mana for Emacs..."
(sit-for 0.01))
Sometimes it’s unclear whether an operation will take a long time to execute or not, or it can be inconvenient to implement a progress reporter. This macro can be used in those situations.
(with-delayed-message (2 (format "Gathering data for %s" entry)) (setq data (gather-data entry)))
In this example, if the body takes more than two seconds to execute, the message will be displayed. If it takes a shorter time than that, the message won’t be displayed. In either case, the body is evaluated as normally, and the return value of the final element in the body is the return value of the macro.
The message element is evaluated before body, and is always evaluated, whether the message is displayed or not.
Almost all the messages displayed in the echo area are also recorded
in the *Messages* buffer so that the user can refer back to
them. This includes all the messages that are output with
message. By default, this buffer is read-only and uses the major
mode messages-buffer-mode. Nothing prevents the user from
killing the *Messages* buffer, but the next display of a message
recreates it. Any Lisp code that needs to access the
*Messages* buffer directly and wants to ensure that it exists
should use the function messages-buffer.
This function returns the *Messages* buffer. If it does not
exist, it creates it, and switches it to messages-buffer-mode.
This variable specifies how many lines to keep in the *Messages*
buffer. The value t means there is no limit on how many lines to
keep. The value nil disables message logging entirely. Here’s
how to display a message and prevent it from being logged:
(let (message-log-max) (message ...))
This variable has the name of the buffer where messages should be
logged to, and defaults to *Messages*. Some packages may find
it useful to temporarily redirect the output to a different buffer
(perhaps to write the buffer out to a log file later), and they can
bind this variable to a different buffer name. (Note that this buffer
(if it doesn’t exist already), will be created and put into
messages-buffer-mode.)
To make *Messages* more convenient for the user, the logging facility combines successive identical messages. It also combines successive related messages for the sake of two cases: question followed by answer, and a series of progress messages.
A question followed by an answer has two messages like the
ones produced by y-or-n-p: the first is ‘question’,
and the second is ‘question...answer’. The first
message conveys no additional information beyond what’s in the second,
so logging the second message discards the first from the log.
A series of progress messages has successive messages like
those produced by make-progress-reporter. They have the form
‘base...how-far’, where base is the same each
time, while how-far varies. Logging each message in the series
discards the previous one, provided they are consecutive.
The functions make-progress-reporter and y-or-n-p
don’t have to do anything special to activate the message log
combination feature. It operates whenever two consecutive messages
are logged that share a common prefix ending in ‘...’.
These variables control details of how the echo area works.
This variable controls where the cursor appears when a message is
displayed in the echo area. If it is non-nil, then the cursor
appears at the end of the message. Otherwise, the cursor appears at
point—not in the echo area at all.
The value is normally nil; Lisp programs bind it to t
for brief periods of time.
This normal hook is run whenever the echo area is cleared—either by
(message nil) or for any other reason.
This variable determines how much time should elapse before command characters echo. Its value must be a number, and specifies the number of seconds to wait before echoing. If the user types a prefix key (such as C-x) and then delays this many seconds before continuing, the prefix key is echoed in the echo area. (Once echoing begins in a key sequence, all subsequent characters in the same key sequence are echoed immediately.)
If the value is zero, then command input is not echoed.
Normally, displaying a long message resizes the echo area to display
the entire message, wrapping long line as needed. But if the variable
message-truncate-lines is non-nil, long lines of
echo-area message are instead truncated to fit the mini-window width.
The variable max-mini-window-height, which specifies the
maximum height for resizing minibuffer windows, also applies to the
echo area (which is really a special use of the minibuffer window;
see Minibuffer 窗口).
Warnings are a facility for a program to inform the user of a possible problem, but continue running (as opposed to signaling an error, see 错误).
Every warning is a textual message, which explains the problem for the user, with the associated severity level which is a symbol. Here are the supported severity levels, in order of decreasing severity, and their meanings:
:emergencyA problem that will seriously impair Emacs operation soon if the user does not attend to it promptly.
:errorA report about data or circumstances that are inherently wrong.
:warningA report about data or circumstances that are not inherently wrong, but raise suspicion of a possible problem.
:debugA report of information that may be useful if the user is currently debugging the Lisp program which issues the warning.
When your program encounters invalid input data, it can either
signal a Lisp error by calling error or signal
(see 如何发出错误信号) or report a warning with severity
:error. Signaling a Lisp error is the easiest thing to do, but
it means the signaling program cannot continue execution. If you want
to take the trouble of implementing a way to continue processing
despite the invalid data, then reporting a warning of severity
:error is the right way of informing the user of the problem.
For instance, the Emacs Lisp byte compiler can report an error that
way and continue compiling other functions. (If the program signals a
Lisp error and then handles it with condition-case, the user
won’t see the error message; reporting that as a warning instead
avoids that problem.)
In addition to severity level, each warning has a warning type
to classify it. The warning type is either a symbol or a list of
symbols. If it is a symbol, it should be the custom group that you
use for the program’s user options; if it is a list, the first element
of the list should be that custom group. For example, byte compiler
warnings use the warning type (bytecomp). If the warning type
is a list, the elements of the list after the first one, which should
be arbitrary symbols, represent subcategories of the warning: they
will be displayed to the user to better explain the nature of the
warning.
This function reports a warning, using the string message as the
warning text and type as the warning type. level should
be the severity level, and defaults to :warning if omitted or
nil.
buffer-name, if non-nil, specifies the name of the buffer
for logging the warning message. By default, it is *Warnings*.
This function reports a warning using the value returned by
(format-message message args…) as the
message text in the *Warnings* buffer. In other respects it is
equivalent to display-warning.
This function reports a warning using the value returned by
(format-message message args…) as the
message text, emacs as the warning type, and :warning as
the severity level. It exists for compatibility only; we recommend
not using it, because you should specify a specific warning type.
Programs can customize how their warnings appear by binding the variables described in this section.
This list defines the meaning and severity order of the warning severity levels. Each element defines one severity level, and they are arranged in order of decreasing severity.
Each element has the form (level string [function]), where level is the severity level it
defines. string specifies the textual description of this
level. string should use ‘%s’ to specify where to put the
warning type information, or it can omit the ‘%s’ so as not to
include that information.
The optional function, if non-nil, is a function to call
with no arguments, to get the user’s attention. A notable example is
ding (see Beeping).
Normally you should not change the value of this variable.
If non-nil, the value is a function to generate prefix text for
warnings. Programs can bind the variable to a suitable function.
display-warning calls this function with the warnings buffer
the current buffer, and the function can insert text into it. That
text becomes the beginning of the warning message.
The function is called with two arguments, the severity level and its
entry in warning-levels. It should return a list to use
instead of that entry (the value need not be an actual member
of warning-levels, but it must have the same structure). By
constructing this value, the function can change the severity of the
warning, or specify different handling for a given severity level.
If the variable’s value is nil, there’s no prefix text, before
the warning is displayed, starting with the string part of the
entry in warning-levels corresponding to the warning’s level.
Programs can bind this variable to t to say that the next
warning should begin a series. When several warnings form a series,
that means to leave point on the first warning of the series, rather
than keep moving it for each warning so that it appears on the last one.
The series ends when the local binding of this variable is unbound and
warning-series becomes nil again.
The value can also be a symbol with a function definition. That is
equivalent to t, except that the next warning will also call
the function with no arguments with the warnings buffer the current
buffer. The function can, for example, insert text which will serve
as a header for the series of warnings.
Once a series has begun, the value of this variable is a marker which points to the buffer position in the warnings buffer of the start of the series.
The variable’s normal value is nil, which means to handle
each warning separately.
When this variable is non-nil, it specifies a fill prefix to
use for filling the text of each warning.
The column at which to fill warnings.
This variable specifies the format for displaying the warning type
in the warning text. The result of formatting the type this way
gets included in the message under the control of the string in the
entry in warning-levels. The default value is " (%s)".
If you bind it to the empty string "" then the warning type
won’t appear at all.
These variables are used by users to control what happens when a Lisp program reports a warning.
This user option controls the window in which the warnings buffer is
shown. By default, the value is t, and Emacs displays the
warnings buffer in a window at the bottom of the selected frame,
creating a new window there if needed. If customized to nil, the
warnings buffer will be shown using the default rules of
display-buffer (see Choosing a Window for Displaying a Buffer); in that case the
warning category can be used in display-buffer-alist to
customize how display-buffer will display these buffers
(see Action Alists for Buffer Display).
This user option specifies the minimum severity level that should be
shown immediately to the user, by popping the warnings buffer in some
window. The default is :warning, which means to show the
warning buffer for any warning severity except :debug. The
warnings of lower severity levels will still be written into the
warnings buffer, but the buffer will not be forced onto display.
This user option specifies the minimum severity level that should be
logged in the warnings buffer. Warnings of lower severity will be
completely ignored: not written to the warnings buffer and not
displayed. The default is :warning, which means to log
warnings of any severity except :debug.
This list specifies which warning types should not be displayed immediately when they occur. Each element of the list should be a list of symbols. If an element of this list has the same elements as the first elements in a warning type, then the warning of that type will not be shown on display by popping the warnings buffer in some window (the warning will still be logged in the warnings buffer).
For example, if the value of this variable is a list like this:
((foo) (bar subtype))
then warnings whose types are foo or (foo) or
(foo something) or (bar subtype other) will not
be shown to the user.
This list specifies which warning types should be ignored: not logged
in the warnings buffer and not shown to the user. The structure and
the matching of warning types are the same as for
warning-suppress-types above.
During startup, Emacs delays showing any warnings until after it
loads and processes the site-wide and user’s init files
(see Summary: Sequence of Actions at Startup). Let-binding (see 局部变量) the
values of these options around some code in your init files which
might emit a warning will therefore not work, because it will not be
in effect by the time the warning is actually processed. Thus, if you
want to suppress some warnings during startup, change the values of
the above options in your init file early enough, or put those
let-binding forms in your after-init-hook or
emacs-startup-hook functions. See The Init File.
Sometimes, you may wish to avoid showing a warning while a command is
running, and only show it only after the end of the command. You can
use the function delay-warning for this. Emacs automatically
delays any warnings emitted during the early stages of startup, and
shows them only after the init files are processed.
This function is the delayed counterpart to display-warning
(see Warning Basics), and it is called with the same arguments.
The warning message is queued into delayed-warnings-list.
The value of this variable is a list of warnings to be displayed after the current command has finished. Each element must be a list
(type message [level [buffer-name]])
with the same form, and the same meanings, as the argument list of
display-warning. Immediately after running
post-command-hook (see 命令循环概述), the Emacs
command loop displays all the warnings specified by this variable,
then resets the variable to nil.
Programs which need to further customize the delayed warnings
mechanism can change the variable delayed-warnings-hook:
This is a normal hook which is run by the Emacs command loop, after
post-command-hook, in order to process and display delayed
warnings. Emacs also runs this hook during startup, after loading the
site-start and user init files (see Summary: Sequence of Actions at Startup), because
warnings emitted before that are automatically delayed.
Its default value is a list of two functions:
(collapse-delayed-warnings display-delayed-warnings)
The function collapse-delayed-warnings removes repeated entries
from delayed-warnings-list. The function
display-delayed-warnings calls display-warning on each
of the entries in delayed-warnings-list, in turn, and then sets
delayed-warnings-list to nil.
You can make characters invisible, so that they do not appear on
the screen, with the invisible property. This can be either a
text property (see Text Properties) or an overlay property
(see Overlays). Cursor motion also partly ignores these
characters; if the command loop finds that point is inside a range of
invisible text after a command, it relocates point to the other side
of the text.
In the simplest case, any non-nil invisible property makes
a character invisible. This is the default case—if you don’t alter
the default value of buffer-invisibility-spec, this is how the
invisible property works. You should normally use t
as the value of the invisible property if you don’t plan
to set buffer-invisibility-spec yourself.
More generally, you can use the variable buffer-invisibility-spec
to control which values of the invisible property make text
invisible. This permits you to classify the text into different subsets
in advance, by giving them different invisible values, and
subsequently make various subsets visible or invisible by changing the
value of buffer-invisibility-spec.
Controlling visibility with buffer-invisibility-spec is
especially useful in a program to display the list of entries in a
database. It permits the implementation of convenient filtering
commands to view just a part of the entries in the database. Setting
this variable is very fast, much faster than scanning all the text in
the buffer looking for properties to change.
This variable specifies which kinds of invisible properties
actually make a character invisible. Setting this variable makes it
buffer-local.
tA character is invisible if its invisible property is
non-nil. This is the default.
Each element of the list specifies a criterion for invisibility; if a
character’s invisible property fits any one of these criteria,
the character is invisible. The list can have two kinds of elements:
atomA character is invisible if its invisible property value is
atom or if it is a list with atom as a member; comparison
is done with eq.
(atom . t)A character is invisible if its invisible property value is
atom or if it is a list with atom as a member; comparison
is done with eq. Moreover, a sequence of such characters
displays as an ellipsis.
Two functions are specifically provided for adding elements to
buffer-invisibility-spec and removing elements from it.
This function adds the element element to
buffer-invisibility-spec. If buffer-invisibility-spec
was t, it changes to a list, (t), so that text whose
invisible property is t remains invisible.
This removes the element element from
buffer-invisibility-spec. This does nothing if element
is not in the list.
A convention for use of buffer-invisibility-spec is that a
major mode should use the mode’s own name as an element of
buffer-invisibility-spec and as the value of the
invisible property:
;; If you want to display an ellipsis: (add-to-invisibility-spec '(my-symbol . t)) ;; If you don’t want ellipsis: (add-to-invisibility-spec 'my-symbol) (overlay-put (make-overlay beginning end) 'invisible 'my-symbol) ;; When done with the invisibility: (remove-from-invisibility-spec '(my-symbol . t)) ;; Or respectively: (remove-from-invisibility-spec 'my-symbol)
You can check for invisibility using the following function:
If pos-or-prop is a marker or number, this function returns a
non-nil value if the text at that position is currently
invisible.
If pos-or-prop is any other kind of Lisp object, that is taken
to mean a possible value of the invisible text or overlay
property. In that case, this function returns a non-nil value
if that value would cause text to become invisible, based on the
current value of buffer-invisibility-spec.
The return value of this function is t if the text would be
completely hidden on display, or a non-nil, non-t value
if the text would be replaced by an ellipsis.
Ordinarily, functions that operate on text or move point do not care
whether the text is invisible, they process invisible characters and
visible characters alike. The user-level line motion commands,
such as next-line, previous-line, ignore invisible
newlines if line-move-ignore-invisible is non-nil (the
default), i.e., behave like these invisible newlines didn’t exist in
the buffer, but only because they are explicitly programmed to do so.
If a command ends with point inside or at the boundary of
invisible text, the main editing loop relocates point to one of the
two ends of the invisible text. Emacs chooses the direction of
relocation so that it is the same as the overall movement direction of
the command; if in doubt, it prefers a position where an inserted char
would not inherit the invisible property. Additionally, if the
text is not replaced by an ellipsis and the command only moved within
the invisible text, then point is moved one extra character so as to
try and reflect the command’s movement by a visible movement of the
cursor.
Thus, if the command moved point back to an invisible range (with the usual stickiness), Emacs moves point back to the beginning of that range. If the command moved point forward into an invisible range, Emacs moves point forward to the first visible character that follows the invisible text and then forward one more character.
These adjustments of point that ended up in the middle of
invisible text can be disabled by setting disable-point-adjustment
to a non-nil value. See 命令执行后的光标位置调整.
Incremental search can make invisible overlays visible temporarily
and/or permanently when a match includes invisible text. To enable
this, the overlay should have a non-nil
isearch-open-invisible property. The property value should be a
function to be called with the overlay as an argument. This function
should make the overlay visible permanently; it is used when the match
overlaps the overlay on exit from the search.
During the search, such overlays are made temporarily visible by
temporarily modifying their invisible and intangible properties. If you
want this to be done differently for a certain overlay, give it an
isearch-open-invisible-temporary property which is a function.
The function is called with two arguments: the first is the overlay, and
the second is nil to make the overlay visible, or t to
make it invisible again.
The invisible property is ignored in text that is covered by a
replacing display property, because such display
properties skip the text without processing its properties.
See Display Specs That Replace The Text.
Selective display refers to a pair of related features for hiding certain lines on the screen.
The first variant, explicit selective display, was designed for use in a Lisp
program: it controls which lines are hidden by altering the text. This kind of
hiding is now obsolete and deprecated; instead you should use the
invisible property (see Invisible Text) to get the same effect.
In the second variant, the choice of lines to hide is made automatically based on indentation. This variant is designed to be a user-level feature.
The way you control explicit selective display is by replacing a newline (control-j) with a carriage return (control-m). The text that was formerly a line following that newline is now hidden. Strictly speaking, it is temporarily no longer a line at all, since only newlines can separate lines; it is now part of the previous line.
Selective display does not directly affect editing commands. For
example, C-f (forward-char) moves point unhesitatingly
into hidden text. However, the replacement of newline characters with
carriage return characters affects some editing commands. For
example, next-line skips hidden lines, since it searches only
for newlines. Modes that use selective display can also define
commands that take account of the newlines, or that control which
parts of the text are hidden.
When you write a selectively displayed buffer into a file, all the control-m’s are output as newlines. This means that when you next read in the file, it looks OK, with nothing hidden. The selective display effect is seen only within Emacs.
This buffer-local variable enables selective display. This means that lines, or portions of lines, may be made hidden.
selective-display is t, then the character
control-m marks the start of hidden text; the control-m, and the rest
of the line following it, are not displayed. This is explicit selective
display.
selective-display is a positive integer, then
lines that start with more than that many columns of indentation are not
displayed.
When some portion of a buffer is hidden, the vertical movement
commands operate as if that portion did not exist, allowing a single
next-line command to skip any number of hidden lines.
However, character movement commands (such as forward-char) do
not skip the hidden portion, and it is possible (if tricky) to insert
or delete text in a hidden portion.
In the examples below, we show the display appearance of the
buffer foo, which changes with the value of
selective-display. The contents of the buffer do not
change.
(setq selective-display nil)
⇒ nil
---------- Buffer: foo ----------
1 on this column
2on this column
3n this column
3n this column
2on this column
1 on this column
---------- Buffer: foo ----------
(setq selective-display 2)
⇒ 2
---------- Buffer: foo ----------
1 on this column
2on this column
2on this column
1 on this column
---------- Buffer: foo ----------
If this buffer-local variable is non-nil, then Emacs displays
‘…’ at the end of a line that is followed by hidden text.
This example is a continuation of the previous one.
(setq selective-display-ellipses t)
⇒ t
---------- Buffer: foo ----------
1 on this column
2on this column ...
2on this column
1 on this column
---------- Buffer: foo ----------
You can use a display table to substitute other text for the ellipsis (‘…’). See Display Tables.
Temporary displays are used by Lisp programs to put output into a buffer and then present it to the user for perusal rather than for editing. Many help commands use this feature.
This function executes the forms in body while arranging to insert
any output they print into the buffer named buffer-name, which is
first created if necessary, and put into Help mode. (See the similar
form with-temp-buffer-window below.) Finally, the buffer is
displayed in some window, but that window is not selected.
If the forms in body do not change the major mode in the output
buffer, so that it is still Help mode at the end of their execution,
then with-output-to-temp-buffer makes this buffer read-only at
the end, and also scans it for function and variable names to make them
into clickable cross-references. See Tips for
Documentation Strings, in particular the item on hyperlinks in
documentation strings, for more details.
The string buffer-name specifies the temporary buffer, which need
not already exist. The argument must be a string, not a buffer. The
buffer is erased initially (with no questions asked), and it is marked
as unmodified after with-output-to-temp-buffer exits.
with-output-to-temp-buffer binds standard-output to the
temporary buffer, then it evaluates the forms in body. Output
using the Lisp output functions within body goes by default to
that buffer (but screen display and messages in the echo area, although
they are “output” in the general sense of the word, are not affected).
See 输出函数.
Several hooks are available for customizing the behavior of this construct; they are listed below.
The value of the last form in body is returned.
---------- Buffer: foo ---------- This is the contents of foo. ---------- Buffer: foo ----------
(with-output-to-temp-buffer "foo"
(print 20)
(print standard-output))
⇒ #<buffer foo>
---------- Buffer: foo ----------
20
#<buffer foo>
---------- Buffer: foo ----------
If this variable is non-nil, with-output-to-temp-buffer
calls it as a function to do the job of displaying a help buffer. The
function gets one argument, which is the buffer it should display.
It is a good idea for this function to run temp-buffer-show-hook
just as with-output-to-temp-buffer normally would, inside of
save-selected-window and with the chosen window and buffer
selected.
This normal hook is run by with-output-to-temp-buffer before
evaluating body. When the hook runs, the temporary buffer is
current. This hook is normally set up with a function to put the
buffer in Help mode.
This normal hook is run by with-output-to-temp-buffer after
displaying the temporary buffer. When the hook runs, the temporary buffer
is current, and the window it was displayed in is selected.
This macro is similar to with-output-to-temp-buffer. Like that
construct, it executes body while arranging to insert any output
it prints into the buffer named buffer-or-name and displays that
buffer in some window. Unlike with-output-to-temp-buffer,
however, it does not automatically switch that buffer to Help mode.
The argument buffer-or-name specifies the temporary buffer. It
can be either a buffer, which must already exist, or a string, in which
case a buffer of that name is created, if necessary. The buffer is
marked as unmodified and read-only when with-temp-buffer-window
exits.
This macro does not call temp-buffer-show-function. Rather, it
passes the action argument to display-buffer
(see Choosing a Window for Displaying a Buffer) in order to display the buffer.
The value of the last form in body is returned, unless the argument quit-function is specified. In that case, it is called with two arguments: the window showing the buffer and the result of body. The final return value is then whatever quit-function returns.
This macro uses the normal hooks temp-buffer-window-setup-hook
and temp-buffer-window-show-hook in place of the analogous hooks
run by with-output-to-temp-buffer.
The two constructs described next are mostly identical to
with-temp-buffer-window but differ from it as specified:
This macro is like with-temp-buffer-window but unlike that makes
the buffer specified by buffer-or-name current for running
body.
A window showing a temporary buffer can be fitted to the size of that buffer using the following mode:
When this minor mode is enabled, windows showing a temporary buffer are automatically resized to fit their buffer’s contents.
A window is resized if and only if it has been specially created for the
buffer. In particular, windows that have shown another buffer before
are not resized. By default, this mode uses fit-window-to-buffer
(see Resizing Windows) for resizing. You can specify a different
function by customizing the options temp-buffer-max-height and
temp-buffer-max-width below.
The effect of this option can be overridden by providing a suitable
window-height, window-width or window-size action
alist entry for display-buffer (see Action Alists for Buffer Display).
This option specifies the maximum height (in lines) of a window
displaying a temporary buffer when temp-buffer-resize-mode is
enabled. It can also be a function to be called to choose the height
for such a buffer. It gets one argument, the buffer, and should return
a positive integer. At the time the function is called, the window to
be resized is selected.
This option specifies the maximum width of a window (in columns)
displaying a temporary buffer when temp-buffer-resize-mode is
enabled. It can also be a function to be called to choose the width for
such a buffer. It gets one argument, the buffer, and should return a
positive integer. At the time the function is called, the window to be
resized is selected.
The following function uses the current buffer for temporary display:
This function momentarily displays string in the current buffer at position. It has no effect on the undo list or on the buffer’s modification status.
The momentary display remains until the next input event. If the next
input event is char, momentary-string-display ignores it
and returns. Otherwise, that event remains buffered for subsequent use
as input. Thus, typing char will simply remove the string from
the display, while typing (say) C-f will remove the string from
the display and later (presumably) move point forward. The argument
char is a space by default.
The return value of momentary-string-display is not meaningful.
If the string string does not contain control characters, you can
do the same job in a more general way by creating (and then subsequently
deleting) an overlay with a before-string property.
See Overlay Properties.
If message is non-nil, it is displayed in the echo area
while string is displayed in the buffer. If it is nil, a
default message says to type char to continue.
In this example, point is initially located at the beginning of the second line:
---------- Buffer: foo ---------- This is the contents of foo. ∗Second line. ---------- Buffer: foo ----------
(momentary-string-display "**** Important Message! ****" (point) ?\r "Type RET when done reading") ⇒ t
---------- Buffer: foo ---------- This is the contents of foo. **** Important Message! ****Second line. ---------- Buffer: foo ---------- ---------- Echo Area ---------- Type RET when done reading ---------- Echo Area ----------
You can use overlays to alter the appearance of a buffer’s text on the screen, for the sake of presentation features. An overlay is an object that belongs to a particular buffer, and has a specified beginning and end. It also has properties that you can examine and set; these affect the display of the text within the overlaid portion of the buffer.
Editing the text of the buffer adjusts the beginning and end of each overlay so that it stays with the text. When you create the overlay, you can specify whether text inserted at the beginning should be inside the overlay or outside, and likewise for the end of the overlay.
This section describes the functions to create, delete and move overlays, and to examine their contents. Overlay changes are not recorded in the buffer’s undo list, since the overlays are not considered part of the buffer’s contents.
This function returns t if object is an overlay.
This function creates and returns an overlay that belongs to buffer and ranges from start to end. Both start and end must specify buffer positions; they may be integers or markers. If buffer is omitted, the overlay is created in the current buffer.
An overlay whose start and end specify the same buffer position is known as empty. A non-empty overlay can become empty if the text between its start and end is deleted. When that happens, the overlay is by default not deleted, but you can cause it to be deleted by giving it the ‘evaporate’ property (see evaporate property).
The arguments front-advance and rear-advance specify what
happens when text is inserted at the beginning (i.e., before
start) and at the end. If they are both nil, the
default, then the overlay extends to include any text inserted at the
beginning, but not text inserted at the end. If front-advance
is non-nil, text inserted at the beginning of the overlay is
excluded from the overlay. If rear-advance is non-nil,
text inserted at the end of the overlay is included in the overlay.
This function returns the position at which overlay starts, as an integer.
This function returns the position at which overlay ends, as an integer.
This function returns the buffer that overlay belongs to. It
returns nil if overlay has been deleted.
This function deletes the specified overlay. The overlay continues to exist as a Lisp object, and its property list is unchanged, but it ceases to be attached to the buffer it belonged to, and ceases to have any effect on display.
A deleted overlay is not permanently disconnected. You can give it a
position in a buffer again by calling move-overlay.
This function moves overlay to buffer, and places its bounds at start and end in that buffer. Both arguments start and end must specify buffer positions; they may be integers or markers.
If buffer is omitted, overlay stays in the same buffer it was already associated with; if overlay was previously deleted (and thus isn’t associated with any buffer), it goes into the current buffer.
The return value is overlay.
This function is the only valid way to change the endpoints of an overlay.
This function clears the text in the region between start and end of any overlays whose property named name has the specified value, such that no such overlay will affect the text in the region. To do this, the function can remove overlays in the region, or move their endpoints, or split them, or do some combination of these. Specifically:
If name is omitted or nil, it means to delete/modify all
overlays that affect text in the specified region. If start
and/or end are omitted or nil, they default to the
beginning and end of the buffer, respectively. Therefore,
(remove-overlays) removes all the overlays in the current buffer.
Values of the named overlay property are compared using eq, which
is important if the values are anything but symbols or fixnums
(see 相等性谓词). It means the values passed to the
function must be the same values used to set the overlay property, not
their copies; objects which are different will not compare equal even if
they have identical contents.
The optional arguments name and value should either both be
passed and non-nil, or both omitted or nil.
This function returns a copy of overlay. The copy has the same endpoints and properties as overlay. However, the text insertion type for the start of the overlay and for the end of the overlay are set to their default values.
Here are some examples:
;; Create an overlay.
(setq foo (make-overlay 1 10))
⇒ #<overlay from 1 to 10 in display.texi>
(overlay-start foo)
⇒ 1
(overlay-end foo)
⇒ 10
(overlay-buffer foo)
⇒ #<buffer display.texi>
;; Give it a property we can check later.
(overlay-put foo 'happy t)
⇒ t
;; Verify the property is present.
(overlay-get foo 'happy)
⇒ t
;; Move the overlay.
(move-overlay foo 5 20)
⇒ #<overlay from 5 to 20 in display.texi>
(overlay-start foo)
⇒ 5
(overlay-end foo)
⇒ 20
;; Delete the overlay. (delete-overlay foo) ⇒ nil ;; Verify it is deleted. foo ⇒ #<overlay in no buffer> ;; A deleted overlay has no position. (overlay-start foo) ⇒ nil (overlay-end foo) ⇒ nil (overlay-buffer foo) ⇒ nil
;; Undelete the overlay. (move-overlay foo 1 20) ⇒ #<overlay from 1 to 20 in display.texi> ;; Verify the results. (overlay-start foo) ⇒ 1 (overlay-end foo) ⇒ 20 (overlay-buffer foo) ⇒ #<buffer display.texi>
;; Moving and deleting the overlay does not change its properties.
(overlay-get foo 'happy)
⇒ t
Overlay properties are like text properties in that the properties that alter how a character is displayed can come from either source. But in most respects they are different. See Text Properties, for comparison.
Text properties are considered a part of the text; overlays and their properties are specifically considered not to be part of the text. Thus, copying text between various buffers and strings preserves text properties, but does not try to preserve overlays. Changing a buffer’s text properties marks the buffer as modified, while moving an overlay or changing its properties does not. Unlike text property changes, overlay property changes are not recorded in the buffer’s undo list.
Since more than one overlay can specify a property value for the same character, Emacs lets you specify a priority value of each overlay. The priority value is used to decide which of the overlapping overlays will “win”.
These functions read and set the properties of an overlay:
This function returns the value of property prop recorded in
overlay, if any. If overlay does not record any value for
that property, but it does have a category property which is a
symbol, that symbol’s prop property is used. Otherwise, the value
is nil.
This function sets the value of property prop recorded in overlay to value. It returns value.
This returns a copy of the property list of overlay.
See also the function get-char-property which checks both
overlay properties and text properties for a given character.
See Examining Text Properties.
Many overlay properties have special meanings; here is a table of them:
priority ¶This property’s value determines the priority of the overlay. If you
want to specify a priority value, use either nil (or zero), or
a positive integer, or a cons of two values. Any other value triggers
undefined behavior.
The priority matters when two or more overlays cover the same
character and both specify the same property with different values;
the one whose priority value is higher overrides the other.
(For the face property, the higher priority overlay’s value
does not completely override the other value; instead, its individual
face attributes override the corresponding face attributes of the
face property whose priority is lower.) If two overlays have
the same priority value, and one is “nested” in the other (i.e.,
covers fewer buffer or string positions), then the inner one will
prevail over the outer one. If neither is nested in the other then
you should not make assumptions about which overlay will prevail.
When a Lisp program puts overlays with defined priorities on text that
might have overlays without priorities, this could cause undesirable
results, because any overlay with a positive priority value will
override all the overlays without a priority. Since most Emacs
features that use overlays don’t specify priorities for their
overlays, integer priorities should be used with care. Instead of
using integer priorities and risk overriding other overlays, you can
use priority values of the form (primary . secondary),
where the primary value is used as described above, and
secondary is the fallback value used when primary and the
nesting considerations fail to resolve the precedence between
overlays. In particular, priority value (nil . n),
with n a positive integer, enables you to have the overlays
ordered by priority when necessary without completely overriding other
overlays.
Currently, all overlays take priority over text properties.
If you need to put overlays in priority order, use the sorted
argument of overlays-at. See Searching for Overlays.
window ¶If the window property is non-nil, then the overlay
applies only on that window.
category ¶If an overlay has a category property, we call it the
category of the overlay. It should be a symbol. The properties
of the symbol serve as defaults for the properties of the overlay.
face ¶This property controls the appearance of the text (see Faces). The value of the property can be the following:
(keyword
value …), where each keyword is a face attribute
name and value is a value for that attribute.
(foreground-color . color-name)
or (background-color . color-name). This specifies the
foreground or background color, similar to (:foreground
color-name) or (:background color-name). This
form is supported for backward compatibility only, and should be
avoided.
mouse-face ¶This property is used instead of face when the mouse is within
the range of the overlay. However, Emacs ignores all face attributes
from this property that alter the text size (e.g., :height,
:weight, and :slant); those attributes are always the
same as in the unhighlighted text.
display ¶This property activates various features that change the
way text is displayed. For example, it can make text appear taller
or shorter, higher or lower, wider or narrower, or replaced with an image.
See The display Property. Note that, if the display property is a
replacing one (see Display Specs That Replace The Text), the invisible
property of the same overlay will be ignored.
help-echo ¶If an overlay has a help-echo property, then when you move the
mouse onto the text in the overlay, Emacs displays a help string in
the echo area, or as a tooltip. For details see Text help-echo.
field ¶Consecutive characters with the same field property constitute a
field. Some motion functions including forward-word and
beginning-of-line stop moving at a field boundary.
See Defining and Using Fields.
modification-hooks ¶This property’s value is a list of functions to be called if any character within the overlay is changed or if text is inserted strictly within the overlay.
The hook functions are called both before and after each change. If the functions save the information they receive, and compare notes between calls, they can determine exactly what change has been made in the buffer text.
When called before a change, each function receives four arguments: the
overlay, nil, and the beginning and end of the text range to be
modified.
When called after a change, each function receives five arguments: the
overlay, t, the beginning and end of the text range just
modified, and the length of the pre-change text replaced by that range.
(For an insertion, the pre-change length is zero; for a deletion, that
length is the number of characters deleted, and the post-change
beginning and end are equal.)
When these functions are called, inhibit-modification-hooks is
bound to non-nil. If the functions modify the buffer, you
might want to bind inhibit-modification-hooks to nil, so
as to cause the change hooks to run for these modifications. However,
doing this may call your own change hook recursively, so be sure to
prepare for that. See Change Hooks.
Text properties also support the modification-hooks property,
but the details are somewhat different (see Properties with Special Meanings).
insert-in-front-hooks ¶This property’s value is a list of functions to be called before and
after inserting text right at the beginning of the overlay. The calling
conventions are the same as for the modification-hooks functions.
insert-behind-hooks ¶This property’s value is a list of functions to be called before and
after inserting text right at the end of the overlay. The calling
conventions are the same as for the modification-hooks functions.
invisible ¶The invisible property can make the text in the overlay
invisible, which means that it does not appear on the screen. However,
if the text covered by the overlay has a replacing display
property, the invisible property will be ignored, because a
replacing display property skips the text without examining its
properties. See Invisible Text, for details.
intangible ¶The intangible property on an overlay works just like the
intangible text property. It is obsolete. See Properties with Special Meanings, for details.
isearch-open-invisibleThis property tells incremental search (see Incremental Search in The GNU Emacs Manual) how to make an invisible overlay visible, permanently, if the final match overlaps it. See Invisible Text.
isearch-open-invisible-temporaryThis property tells incremental search how to make an invisible overlay visible, temporarily, during the search. See Invisible Text.
before-string ¶This property’s value is a string to add to the display at the beginning of the overlay. The string does not appear in the buffer in any sense—only on the screen. Note that if the text at the beginning of the overlay is made invisible, the string will not be displayed.
after-string ¶This property’s value is a string to add to the display at the end of the overlay. The string does not appear in the buffer in any sense—only on the screen. Note that if the text at the end of the overlay is made invisible, the string will not be displayed.
line-prefixThis property specifies a display spec to prepend to each non-continuation line at display-time. See Truncation.
wrap-prefixThis property specifies a display spec to prepend to each continuation line at display-time. See Truncation.
evaporate ¶If this property is non-nil, the overlay is deleted automatically
if it becomes empty (i.e., if its length becomes zero). If you give
an empty overlay (see empty overlay) a
non-nil evaporate property, that deletes it immediately.
Note that, unless an overlay has this property, it will not be deleted
when the text between its starting and ending positions is deleted
from the buffer.
display-line-numbers-disable ¶This property prevents display of line numbers (see display-line-numbers in The GNU Emacs Manual) for the text which is within an overlay having this property. One situation where using an overlay with this property is useful is an empty overlay at end-of-buffer, since otherwise there’s no way of preventing the display of the line number there.
keymap ¶If this property is non-nil, it specifies a keymap for a
portion of the text. This keymap takes precedence over most other
keymaps (see 活跃按键映射表), and it is used when point is within
the overlay, where the front-
and rear-advance properties define whether the boundaries are
considered as being within or not.
local-map ¶The local-map property is similar to keymap but replaces the
buffer’s local map rather than augmenting existing keymaps. This also means it
has lower precedence than minor mode keymaps.
The keymap and local-map properties do not affect a
string displayed by the before-string, after-string, or
display properties. This is only relevant for mouse clicks and
other mouse events that fall on the string, since point is never on
the string. To bind special mouse events for the string, assign it a
keymap or local-map text property. See Properties with Special Meanings.
This function returns a list of all the overlays that cover the character at
position pos in the current buffer. If sorted is non-nil,
the list is in decreasing order of priority, otherwise it is in no particular
order. An overlay contains position pos if it begins at or before
pos, and ends after pos.
To illustrate usage, here is a Lisp function that returns a list of the overlays that specify property prop for the character at point:
(defun find-overlays-specifying (prop)
(let ((overlays (overlays-at (point)))
found)
(while overlays
(let ((overlay (car overlays)))
(if (overlay-get overlay prop)
(setq found (cons overlay found))))
(setq overlays (cdr overlays)))
found))
This function returns a list of the overlays that overlap the region beg through end. An overlay overlaps with a region if it contains one or more characters in the region; empty overlays (see empty overlay) overlap if they are at beg, strictly between beg and end, or at end when end denotes the position at the end of the accessible part of the buffer.
This function returns the buffer position of the next beginning or end
of an overlay, after pos. If there is none, it returns
(point-max).
This function returns the buffer position of the previous beginning or
end of an overlay, before pos. If there is none, it returns
(point-min).
As an example, here’s a simplified (and inefficient) version of the
primitive function next-single-char-property-change
(see Text Property Search Functions). It searches forward from position
pos for the next position where the value of a given property
prop, as obtained from either overlays or text properties,
changes.
(defun next-single-char-property-change (position prop)
(save-excursion
(goto-char position)
(let ((propval (get-char-property (point) prop)))
(while (and (not (eobp))
(eq (get-char-property (point) prop) propval))
(goto-char (min (next-overlay-change (point))
(next-single-property-change (point) prop)))))
(point)))
Since not all characters have the same width, these functions let you check the width of a character. See Indentation Primitives, and Motion by Screen Lines, for related functions.
This function returns the width in columns of the character
char, if it were displayed in the current buffer (i.e., taking
into account the buffer’s display table, if any; see Display Tables). The width of a tab character is usually tab-width
(see Usual Display Conventions).
Return non-nil if char is an uppercase character
according to Unicode.
This function returns the width in columns of the string string,
if it were displayed in the current buffer and the selected window.
Optional arguments from and to specify the substring of
string to consider, and are interpreted as in substring
(see 创建字符串).
The return value is an approximation: it only considers the values
returned by char-width for the constituent characters, always
takes a tab character as taking tab-width columns, ignores
display properties and fonts, etc. For these reasons, we recommend
using window-text-pixel-size or string-pixel-width,
described below, instead.
This function returns a new string that is a truncation of string which fits within width columns on display.
If string is narrower than width, the result is equal to string; otherwise excess characters are omitted from the result. If a multi-column character in string exceeds the goal width, that character is omitted from the result. Thus, the result can sometimes fall short of width, but cannot go beyond it.
The optional argument start-column specifies the starting
column; it defaults to zero. If this is non-nil, then the
first start-column columns of the string are omitted from the
result. If one multi-column character in string extends across
the column start-column, that character is omitted.
The optional argument padding, if non-nil, is a padding
character added at the beginning and end of the result string, to
extend it to exactly width columns. The padding character is
appended at the end of the result if it falls short of width, as
many times as needed to reach width. It is also prepended at
the beginning of the result if a multi-column character in
string extends across the column start-column.
If ellipsis is non-nil, it should be a string which will
replace the end of string when it is truncated. In this case,
more characters will be removed from string to free enough space
for ellipsis to fit within width columns. However, if
the display width of string is less than the display width of
ellipsis, ellipsis will not be appended to the result. If
ellipsis is non-nil and not a string, it stands for the
value returned by the function truncate-string-ellipsis,
described below.
The optional argument ellipsis-text-property, if non-nil,
means hide the excess parts of string with a display text
property (see The display Property) showing the ellipsis, instead of
actually truncating the string.
(truncate-string-to-width "\tab\t" 12 4)
⇒ "ab"
(truncate-string-to-width "\tab\t" 12 4 ?\s)
⇒ " ab "
This function uses string-width and char-width to find
the suitable truncation point when string is too wide, so it
suffers from the same basic issues as string-width does. In
particular, when character composition happens within string,
the display width of a string could be smaller than the sum of widths
of the constituent characters, and this function might return
inaccurate results.
This function returns the string to be used as an ellipses in
truncate-string-to-width and other similar contexts. The value
is that of the variable truncate-string-ellipsis, if it’s
non-nil, the string with the single character U+2026
HORIZONTAL ELLIPSIS if that character can be displayed on the
selected frame, and the string ‘...’ otherwise.
The following function returns the size in pixels of text as if it were
displayed in a given window. This function is used by
fit-window-to-buffer and fit-frame-to-buffer
(see Resizing Windows) to make a window exactly as large as the text
it contains.
This function returns the dimensions of the text of window’s buffer in pixels. window must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width of any text line and the maximum pixel-height of all text lines. This function exists to allow Lisp programs to adjust the dimensions of window to the buffer text it needs to display, and for other similar situations.
The return value can also optionally (see below) include the buffer position of the first line whose dimensions were measured.
The optional argument from, if non-nil, specifies the
first text position to consider, and defaults to the minimum
accessible position of the buffer. If from is t, it
stands for the minimum accessible position that is not a newline
character. If from is a cons, its car specifies a buffer
position, and its cdr specifies the vertical offset in pixels
from that position to the first screen line whose text is to be
measured. (The measurement will start from the visual beginning of
that screen line.) In that case, the return value will instead be a
list of the pixel-width, pixel-height, and the buffer position of the
first line that was measured. The optional argument to, if
non-nil, specifies the last text position to consider, and
defaults to the maximum accessible position of the buffer. If
to is t, it stands for the maximum accessible position
that is not a newline character.
The optional argument x-limit, if non-nil, specifies the
maximum X coordinate beyond which text should be ignored; it is
therefore also the largest value of pixel-width that the function can
return. If x-limit nil or omitted, it means to use the
pixel-width of window’s body (see Window Sizes); this
default means that text of truncated lines wider than the window will
be ignored. This default is useful when the caller does not intend to
change the width of window. Otherwise, the caller should
specify here the maximum width window’s body may assume; in
particular, if truncated lines are expected and their text needs to be
accounted for, x-limit should be set to a large value. Since
calculating the width of long lines can take some time, it’s always a
good idea to make this argument as small as needed; in particular, if
the buffer might contain long lines that will be truncated anyway.
The optional argument y-limit, if non-nil, specifies the
maximum Y coordinate beyond which text is to be ignored; it is
therefore also the maximum pixel-height that the function can return.
If y-limit is nil or omitted, it means to consider all the
lines of text till the buffer position specified by to. Since
calculating the pixel-height of a large buffer can take some time, it
makes sense to specify this argument; in particular, if the caller
does not know the size of the buffer.
The optional argument mode-lines nil or omitted means to
not include the height of the mode-, tab- or header-line of window
in the return value. If it is either the symbol mode-line,
tab-line or header-line, include only the height of that
line, if present, in the return value. If it is t, include the
height of all of these lines, if present, in the return value.
The optional argument ignore-line-at-end controls whether or not to count the height of text in to’s screen line as part of the returned pixel-height. This is useful if your Lisp program is only interested in the dimensions of text up to and excluding the visual beginning of to’s screen line.
window-text-pixel-size treats the text displayed in a window as a
whole and does not care about the size of individual lines. The
following function does.
This function calculates the pixel dimensions of each line displayed in the specified window. It does so by walking window’s current glyph matrix—a matrix storing the glyph (see Glyphs) of each buffer character currently displayed in window. If successful, it returns a list of cons pairs representing the x- and y-coordinates of the lower right corner of the last character of each line. Coordinates are measured in pixels from an origin (0, 0) at the top-left corner of window. window must be a live window and defaults to the selected one.
If the optional argument first is an integer, it denotes the index
(starting with 0) of the first line of window’s glyph matrix to be
returned. Note that if window has a header line, the line with
index 0 is that header line. If first is nil, the first line to
be considered is determined by the value of the optional argument
body: If body is non-nil, this means to start with
the first line of window’s body, skipping any header line, if
present. Otherwise, this function will start with the first line of
window’s glyph matrix, possibly the header line.
If the optional argument last is an integer, it denotes the index
of the last line of window’s glyph matrix that shall be returned.
If last is nil, the last line to be considered is determined by
the value of body: If body is non-nil, this means to
use the last line of window’s body, omitting window’s mode
line, if present. Otherwise, this means to use the last line of
window which may be the mode line.
The optional argument inverse, if nil, means that the
y-pixel value returned for any line specifies the distance in pixels
from the left edge (body edge if body is non-nil) of
window to the right edge of the last glyph of that line.
inverse non-nil means that the y-pixel value returned for
any line specifies the distance in pixels from the right edge of the
last glyph of that line to the right edge (body edge if body is
non-nil) of window. This is useful for determining the
amount of slack space at the end of each line.
The optional argument left, if non-nil means to return the
x- and y-coordinates of the lower left corner of the leftmost character
on each line. This is the value that should be used for windows that
mostly display text from right to left.
If left is non-nil and inverse is nil, this
means that the y-pixel value returned for any line specifies the
distance in pixels from the left edge of the last (leftmost) glyph of
that line to the right edge (body edge if body is non-nil)
of window. If left and inverse are both
non-nil, the y-pixel value returned for any line specifies the
distance in pixels from the left edge (body edge if body is
non-nil) of window to the left edge of the last (leftmost)
glyph of that line.
This function returns nil if the current glyph matrix of
window is not up-to-date which usually happens when Emacs is busy,
for example, when processing a command. The value should be retrievable
though when this function is run from an idle timer with a delay of zero
seconds.
This is much like window-text-pixel-size, but can be used when
the buffer isn’t shown in a window. (window-text-pixel-size is
faster when it is, so this function shouldn’t be used in that case.)
buffer-or-name must specify a live buffer or the name of a live buffer and defaults to the current buffer. window must be a live window and defaults to the selected one; the function will compute the text dimensions as if buffer is displayed in window. The return value is a cons of the maximum pixel-width of any text line and the pixel-height of all the text lines of the accessible portion of the buffer specified by buffer-or-name.
The optional arguments x-limit and y-limit have the same
meaning as with window-text-pixel-size.
If you want to measure dimensions of some part of the buffer text, narrow the buffer to that part before calling this function (see Narrowing).
This is a convenience function that uses window-text-pixel-size
to compute the width of string (in pixels). Caveat: if you call
this function to measure the width of a string with embedded newlines,
it will then return the width of the widest substring that does not
include newlines. The meaning of this result is the widest line taken
by the string if inserted into a buffer.
This function returns the height in pixels of the line at point in the selected window. The value includes the line spacing of the line (see Line Height).
When character compositions are in effect, sequence of characters can be composed for display to form grapheme clusters, for example to display accented characters, or ligatures, or Emoji, or when complex text shaping requires that for some scripts. When that happens, characters no longer map in a simple way to display columns, and display layout decisions with such strings, such as truncating too wide strings, can be a complex job. This function helps in performing such jobs: it splits up its argument string into a list of substrings, where each substring produces a single grapheme cluster that should be displayed as a unit. Lisp programs can then use this list to construct visually-valid substrings of string which will look correctly on display, or compute the width of any substring of string by adding the width of its constituents in the returned list, etc.
For instance, if you want to display a string without the first glyph, you can say:
(apply #'insert (cdr (string-glyph-split string))))
When a buffer is displayed with line numbers (see Display Custom in The GNU Emacs Manual), it is sometimes useful to know the width taken for displaying the line numbers. The following function is for Lisp programs which need this information for layout calculations.
This function returns the width used for displaying the line numbers
in the selected window. If the optional argument pixelwise is
the symbol columns, the return value is a float number of the
frame’s canonical columns; if pixelwise is t or any other
non-nil value, the value is an integer and is measured in
pixels. If pixelwise is omitted or nil, the value is the
integer number of columns of the font defined for the
line-number face, and doesn’t include the 2 columns used to pad
the numbers on display. If line numbers are not displayed in the
selected window, the value is zero regardless of the value of
pixelwise. Use with-selected-window (see Selecting Windows) if you need this information about another window.
The total height of each display line consists of the height of the contents of the line, plus optional additional vertical line spacing above or below the display line.
The height of the line contents is the maximum height of any character or image on that display line, including the final newline if there is one. (A display line that is continued doesn’t include a final newline.) That is the default line height, if you do nothing to specify a greater height. (In the most common case, this equals the height of the corresponding frame’s default font, see Frame Font.)
There are several ways to explicitly specify a larger line height, either by specifying an absolute height for the display line, or by specifying vertical space. However, no matter what you specify, the actual line height can never be less than the default.
A newline can have a line-height text or overlay property
that controls the total height of the display line ending in that
newline. The property value can be one of several forms:
tIf the property value is t, the newline character has no
effect on the displayed height of the line—the visible contents
alone determine the height. The line-spacing property of the
newline, described below, is also ignored in this case. This is
useful for tiling small images (or image slices) without adding blank
areas between the images.
(height total)If the property value is a list of the form shown, that adds extra
space below the display line. First Emacs uses height as
a height spec to control extra space above the line; then it
adds enough space below the line to bring the total line height
up to total. In this case, any value of line-spacing
property for the newline is ignored.
Any other kind of property value is a height spec, which translates into a number—the specified line height. There are several ways to write a height spec; here’s how each of them translates into a number:
integerIf the height spec is a positive integer, the height value is that integer.
floatIf the height spec is a float, float, the numeric height value is float times the frame’s default line height.
(face . ratio)If the height spec is a cons of the format shown, the numeric height
is ratio times the height of face face. ratio can
be any type of number, or nil which means a ratio of 1.
If face is t, it refers to the current face.
(nil . ratio)If the height spec is a cons of the format shown, the numeric height is ratio times the height of the contents of the line.
Thus, any valid height spec determines the height in pixels, one way or another. If the line contents’ height is less than that, Emacs adds extra vertical space above the line to achieve the specified total height.
If you don’t specify the line-height property, the line’s
height consists of the contents’ height plus the line spacing.
There are several ways to specify the line spacing for different
parts of Emacs text.
On graphical terminals, you can specify the line spacing for all
lines in a frame, using the line-spacing frame parameter
(see Layout Parameters). However, if the default value of
line-spacing is non-nil, it overrides the
frame’s line-spacing parameter. An integer specifies the
number of pixels put below lines. A floating-point number specifies
the spacing relative to the frame’s default line height.
You can specify the line spacing for all lines in a buffer via the
buffer-local line-spacing variable. An integer specifies
the number of pixels put below lines. A floating-point number
specifies the spacing relative to the default frame line height. This
overrides line spacings specified for the frame.
Finally, a newline can have a line-spacing text or overlay
property that can enlarge the default frame line spacing and the
buffer local line-spacing variable: if its value is larger than
the buffer or frame defaults, that larger value is used instead, for
the display line ending in that newline (unless the newline also has
the line-height property whose value is one of the special
values which cause line-spacing to be ignored, see above).
One way or another, these mechanisms specify a Lisp value for the spacing of each line. The value is a height spec, and it translates into a Lisp value as described above. However, in this case the numeric height value specifies the line spacing, rather than the line height.
On text terminals, the line spacing cannot be altered.
A face is a collection of graphical attributes for displaying text: font, foreground color, background color, optional underlining, etc. Faces control how Emacs displays text in buffers, as well as other parts of the frame such as the mode line.
One way to represent a face is as a property list of attributes,
like (:foreground "red" :weight bold). Such a list is called
an anonymous face. For example, you can assign an anonymous
face as the value of the face text property, and Emacs will
display the underlying text with the specified attributes.
See Properties with Special Meanings.
More commonly, a face is referred to via a face name: a Lisp
symbol associated with a set of face attributes30. Named faces are
defined using the defface macro (see Defining Faces).
Emacs comes with several standard named faces (see Basic Faces).
Some parts of Emacs require named faces (e.g., the functions documented in Face Attribute Functions). Unless otherwise stated, we will use the term face to refer only to named faces.
This function returns a non-nil value if object is a
named face: a Lisp symbol or string which serves as a face name.
Otherwise, it returns nil.
Face attributes determine the visual appearance of a face. The following table lists all the face attributes, their possible values, and their effects.
Apart from the values given below, each face attribute can have the
value unspecified. This special value means that the face
doesn’t specify that attribute directly. An unspecified
attribute tells Emacs to refer instead to a parent face (see the
description :inherit attribute below); or, failing that, to an
underlying face (see Displaying Faces). (However,
unspecified is not a valid value in defface.)
A face attribute can also have the value reset. This special
value stands for the value of the corresponding attribute of the
default face.
The default face must explicitly specify all attributes, and
cannot use the special value reset.
Some of these attributes are meaningful only on certain kinds of displays. If your display cannot handle a certain attribute, the attribute is ignored.
:familyFont family name (a string). See Fonts in The GNU
Emacs Manual, for more information about font families. The function
font-family-list (see below) returns a list of available family
names.
:foundryThe name of the font foundry for the font family specified by
the :family attribute (a string). See Fonts in The
GNU Emacs Manual.
:widthRelative character width. This should be one of the symbols
ultra-condensed, extra-condensed, condensed,
semi-condensed, normal, regular, medium,
semi-expanded, expanded, extra-expanded, or
ultra-expanded.
:heightThe height of the font. In the simplest case, this is an integer in units of 1/10 point.
The value can also be floating point or a function, which specifies the height relative to an underlying face (see Displaying Faces). A floating-point value specifies the amount by which to scale the height of the underlying face. A function value is called with one argument, the height of the underlying face, and returns the height of the new face. If the function is passed an integer argument, it must return an integer.
The height of the default face must be specified using an integer; floating point and function values are not allowed.
:weightFont weight—one of the symbols (from densest to faintest)
ultra-bold, extra-bold, bold, semi-bold,
normal, semi-light, light, extra-light, or
ultra-light. On text terminals which support
variable-brightness text, any weight greater than normal is displayed
as extra bright, and any weight less than normal is displayed as
half-bright.
:slant ¶Font slant—one of the symbols italic, oblique,
normal, reverse-italic, or reverse-oblique. On
text terminals that support variable-brightness text, slanted text is
displayed as half-bright.
:foregroundForeground color, a string. The value can be a system-defined color name, or a hexadecimal color specification. See Color Names. On black-and-white displays, certain shades of gray are implemented by stipple patterns.
:distant-foregroundAlternative foreground color, a string. This is like :foreground
but the color is only used as a foreground when the background color is
near to the foreground that would have been used. This is useful for
example when marking text (i.e., the region face). If the text has a foreground
that is visible with the region face, that foreground is used.
If the foreground is near the region face background,
:distant-foreground is used instead so the text is readable.
:backgroundBackground color, a string. The value can be a system-defined color name, or a hexadecimal color specification. See Color Names.
:underline ¶Whether or not characters should be underlined, and in what
way. The possible values of the :underline attribute are:
nilDon’t underline.
tUnderline with the foreground color of the face.
Underline in color color, a string specifying a color.
(:color color :style style :position position)color is either a string, or the symbol foreground-color,
meaning the foreground color of the face. Omitting the attribute
:color means to use the foreground color of the face.
style is a symbol which sets the line-style to of the underline.
It should be one of line, double-line, wave,
dots, or dashes. GUI frames under most window systems
support all the aforementioned underline styles, while on text terminals
double-line, wave and dots are contingent on the
availability of the Smulx or Su terminfo capabilities.
Omitting the attribute :style means to use a straight line.
position, if non-nil, means to display the underline at the
descent of the text, instead of at the baseline level. If it is a
number, then it specifies the amount of pixels above the descent to
display the underline.
:overline ¶Whether or not characters should be overlined, and in what color.
If the value is t, overlining uses the foreground color of the
face. If the value is a string, overlining uses that color. The
value nil means do not overline.
:strike-through ¶Whether or not characters should be strike-through, and in what
color. The value is used like that of :overline.
:box ¶Whether or not a box should be drawn around characters, its color, the
width of the box lines, and 3D appearance. Here are the possible
values of the :box attribute, and what they mean:
nilDon’t draw a box.
tDraw a box with lines of width 1, in the foreground color.
Draw a box with lines of width 1, in color color.
(:line-width (vwidth . hwidth) :color color :style style)You can explicitly specify all aspects of the box with a plist of this form. Any element in this plist can be omitted.
The values of vwidth and hwidth specify respectively the
width of the vertical and horizontal lines to draw; they default to (1
. 1). A negative horizontal or vertical width −n means
to draw a line of width n that occupies the space of the
underlying text, thus avoiding any increase in the character height or
width. For simplification the width could be specified with only a
single number n instead of a list, such case is equivalent to
((abs n) . n).
The value of color specifies the color to draw with. The default
is the background color of the face for 3D boxes and
flat-button, and the foreground color of the face for other
boxes.
The value of style specifies whether to draw a 3D box. If it is
released-button, the box looks like a 3D button that is not
being pressed. If it is pressed-button, the box looks like a
3D button that is being pressed. If it is nil,
flat-button or omitted, a plain 2D box is used.
If you use the :box face attribute on strings displayed instead
of buffer text via the display text property, special
considerations might apply if the surrounding buffer text also has the
:box face attribute. See Display Specs That Replace The Text. Also note that the
vertical lines of the box are only drawn when :box attribute
changes from nil to non-nil or vice versa; two consecutive
face properties with a non-nil :box attribute will be
displayed without the vertical line between them.
:inverse-videoWhether or not characters should be displayed in inverse video. The
value should be t (yes) or nil (no).
:stippleThe background stipple, a bitmap.
The value can be a string; that should be the name of a file containing
external-format X bitmap data. The file is found in the directories
listed in the variable x-bitmap-file-path.
Alternatively, the value can specify the bitmap directly, with a list
of the form (width height data). Here,
width and height specify the size in pixels, and
data is a string containing the raw bits of the bitmap, row by
row. Each row occupies \((\mathit{width} + 7) / 8\) consecutive bytes
in the string (which should be a unibyte string for best results).
This means that each row always occupies at least one whole byte.
If the value is nil, that means use no stipple pattern.
Normally you do not need to set the stipple attribute, because it is used automatically to handle certain shades of gray.
:fontThe font used to display the face. Its value should be a font object or a fontset. If it is a font object, it specifies the font to be used by the face for displaying ASCII characters. See Low-Level Font Representation, for information about font objects, font specs, and font entities. See Fontsets, for information about fontsets.
When specifying this attribute using set-face-attribute or
set-face-font (see Face Attribute Functions), you may also
supply a font spec, a font entity, or a string. Emacs converts such
values to an appropriate font object, and stores that font object as
the actual attribute value. If you specify a string, the contents of
the string should be a font name (see Fonts in The GNU Emacs
Manual); if the font name is an XLFD containing wildcards, Emacs
chooses the first font matching those wildcards. Specifying this
attribute also changes the values of the :family,
:foundry, :width, :height, :weight, and
:slant attributes.
:inherit ¶The name of a face from which to inherit attributes, or a list of face
names. Attributes from inherited faces are merged into the face like
an underlying face would be, with higher priority than underlying
faces (see Displaying Faces). If the face to inherit from is
unspecified, it is treated the same as nil, since Emacs
never merges :inherit attributes. If a list of faces is used,
attributes from faces earlier in the list override those from later
faces.
:extendWhether or not this face will be extended beyond end of line and will
affect the display of the empty space between the end of line and the
edge of the window. The value should be t to display the empty
space between end of line and edge of the window using this face, or
nil to not use this face for the space between the end of the
line and the edge of the window. When Emacs merges several faces for
displaying the empty space beyond end of line, only those faces with
:extend non-nil will be merged. By default, only a
small number of faces, notably, region, have this attribute
set. This attribute is different from the others in that when a theme
doesn’t specify an explicit value for a face, the value from the
original face definition by defface is inherited
(see Defining Faces).
Some modes, like hl-line-mode, use a face with an
:extend property to mark the entire current line. Note,
however, that Emacs will always allow you to move point after the
final character in a buffer, and if the buffer ends with a newline
character, point can be placed on what is seemingly a line at the end
of the buffer—but Emacs can’t highlight that “line”, because it
doesn’t really exist.
This function returns a list of available font family names. The
optional argument frame specifies the frame on which the text is
to be displayed; if it is nil, the selected frame is used.
This variable specifies the minimum distance between the baseline and the underline, in pixels, when displaying underlined text.
This variable specifies a list of directories for searching
for bitmap files, for the :stipple attribute.
This returns t if object is a valid bitmap specification,
suitable for use with :stipple (see above). It returns
nil otherwise.
The usual way to define a face is through the defface macro.
This macro associates a face name (a symbol) with a default face
spec. A face spec is a construct which specifies what attributes a
face should have on any given terminal; for example, a face spec might
specify one foreground color on high-color terminals, and a different
foreground color on low-color terminals.
People are sometimes tempted to create a variable whose value is a
face name. In the vast majority of cases, this is not necessary; the
usual procedure is to define a face with defface, and then use
its name directly.
Note that once you have defined a face (usually with defface),
you cannot later undefine this face safely, except by restarting
Emacs.
This macro declares face as a named face whose default face spec
is given by spec. You should not quote the symbol face,
and it should not end in ‘-face’ (that would be redundant). The
argument doc is a documentation string for the face. The
additional keyword arguments have the same meanings as in
defgroup and defcustom (see 通用项关键字).
If face already has a default face spec, this macro does nothing.
The default face spec determines face’s appearance when no customizations are in effect (see 自定义设置). If face has already been customized (via Custom themes or via customizations read from the init file), its appearance is determined by the custom face spec(s), which override the default face spec spec. However, if the customizations are subsequently removed, the appearance of face will again be determined by its default face spec.
As an exception, if you evaluate a defface form with
C-M-x (eval-defun) or with C-x C-e
(eval-last-sexp) in Emacs Lisp mode, a special feature of these
commands overrides any custom face specs on the face, causing the face
to reflect exactly what the defface says.
The spec argument is a face spec, which states how the face should appear on different kinds of terminals. It should be an alist whose elements each have the form
(display . plist)
display specifies a class of terminals (see below). plist
is a property list of face attributes and their values, specifying how
the face appears on such terminals. For backward compatibility, you
can also write an element as (display plist).
The display part of an element of spec determines which terminals the element matches. If more than one element of spec matches a given terminal, the first element that matches is the one used for that terminal. There are three possibilities for display:
defaultThis element of spec doesn’t match any terminal; instead, it specifies defaults that apply to all terminals. This element, if used, must be the first element of spec. Each of the following elements can override any or all of these defaults.
tThis element of spec matches all terminals. Therefore, any
subsequent elements of spec are never used. Normally t
is used in the last (or only) element of spec.
If display is a list, each element should have the form
(characteristic value…). Here
characteristic specifies a way of classifying terminals, and the
values are possible classifications which display should
apply to. Here are the possible values of characteristic:
typeThe kind of window system the terminal uses—either graphic
(any graphics-capable display), x, pc (for the MS-DOS
console), w32 (for MS Windows 9X/NT/2K/XP), haiku (for
Haiku), pgtk (for pure GTK), android (for Android), or
tty (a non-graphics-capable display). See window-system.
classWhat kinds of colors the terminal supports—either color,
grayscale, or mono.
backgroundThe kind of background—either light or dark.
min-colorsAn integer that represents the minimum number of colors the terminal
should support. This matches a terminal if its
display-color-cells value is at least the specified integer.
supportsWhether or not the terminal can display the face attributes given in value… (see Face Attributes). See Display Face Attribute Testing, for more information on exactly how this testing is done.
If an element of display specifies more than one value for a given characteristic, any of those values is acceptable. If display has more than one element, each element should specify a different characteristic; then each characteristic of the terminal must match one of the values specified for it in display.
For example, here’s the definition of the standard face
highlight:
(defface highlight
'((((class color) (min-colors 88) (background light))
:background "darkseagreen2")
(((class color) (min-colors 88) (background dark))
:background "darkolivegreen")
(((class color) (min-colors 16) (background light))
:background "darkseagreen2")
(((class color) (min-colors 16) (background dark))
:background "darkolivegreen")
(((class color) (min-colors 8))
:background "green" :foreground "black")
(t :inverse-video t))
"Basic face for highlighting."
:group 'basic-faces)
Internally, Emacs stores each face’s default spec in its
face-defface-spec symbol property (see 符号属性).
The saved-face property stores any face spec saved by the user
using the customization buffer; the customized-face property
stores the face spec customized for the current session, but not
saved; and the theme-face property stores an alist associating
the active customization settings and Custom themes with the face
specs for that face. The face’s documentation string is stored in the
face-documentation property.
Normally, a face is declared just once, using defface, and
any further changes to its appearance are applied using the Customize
framework (e.g., via the Customize user interface or via the
custom-set-faces function; see 应用自定义设置), or
by face remapping (see Face Remapping). In the rare event that
you need to change a face spec directly from Lisp, you can use the
face-spec-set function.
This function applies spec as a face spec for face.
spec should be a face spec, as described in the above
documentation for defface.
This function also defines face as a valid face name if it is not already one, and (re)calculates its attributes on existing frames.
The optional argument spec-type determines which spec to set.
If it is omitted or nil or face-override-spec, this
function sets the override spec, which overrides face specs on
face of all the other types mentioned below. This is useful
when calling this function outside of Custom code. If spec-type
is customized-face or saved-face, this function sets the
customized spec or the saved custom spec, respectively. If it is
face-defface-spec, this function sets the default face spec
(the same one set by defface). If it is reset, this
function clears out all customization specs and override specs from
face (in this case, the value of spec is ignored). The
effect of any other value of spec-type on the face specs is
reserved for internal use, but the function will still define
face itself and recalculate its attributes, as described above.
This section describes functions for directly accessing and modifying the attributes of a named face.
This function returns the value of the attribute attribute for face on frame. See Face Attributes, for the supported attributes.
If frame is omitted or nil, that means the selected frame
(see Input Focus). If frame is t, this function
returns the value of the specified attribute for newly-created frames,
i.e. the value of the attribute before applying the face spec in the
face’s defface definition (see Defining Faces) or the spec
set by face-spec-set. This default value of attribute is
normally unspecified, unless you have specified some other
value using set-face-attribute; see below.
If inherit is nil, only attributes directly defined by
face are considered, so the return value may be
unspecified, or a relative value. If inherit is
non-nil, face’s definition of attribute is merged
with the faces specified by its :inherit attribute; however the
return value may still be unspecified or relative. If
inherit is a face or a list of faces, then the result is further
merged with that face (or faces), until it becomes specified and
absolute.
To ensure that the return value is always specified and absolute, use
a value of default for inherit; this will resolve any
unspecified or relative values by merging with the default face
(which is always completely specified).
For example,
(face-attribute 'bold :weight)
⇒ bold
This function returns non-nil if value, when used as the
value of the face attribute attribute, is relative. This means
it would modify, rather than completely override, any value that comes
from a subsequent face in the face list or that is inherited from
another face.
unspecified is a relative value for all attributes. For
:height, floating point and function values are also relative.
For example:
(face-attribute-relative-p :height 2.0)
⇒ t
This function returns an alist of attributes of face. The
elements of the result are name-value pairs of the form
(attr-name . attr-value). Optional argument
frame specifies the frame whose definition of face to
return; if omitted or nil, the returned value describes the
default attributes of face for newly created frames, i.e. the
values these attributes have before applying the face spec in the
face’s defface definition or the spec set by
face-spec-set. These default values of the attributes are
normally unspecified, unless you have specified some other
value using set-face-attribute; see below.
If value1 is a relative value for the face attribute attribute, returns it merged with the underlying value value2; otherwise, if value1 is an absolute value for the face attribute attribute, returns value1 unchanged.
Normally, Emacs uses the face specs of each face to automatically
calculate its attributes on each frame (see Defining Faces). The
function set-face-attribute can override this calculation by
directly assigning attributes to a face, either on a specific frame or
for all frames. This function is mostly intended for internal usage.
This function sets one or more attributes of face for frame. The attributes specified in this way override the face spec(s) belonging to face. See Face Attributes, for the supported attributes.
The extra arguments arguments specify the attributes to set, and
the values for them. They should consist of alternating attribute
names (such as :family or :underline) and values. Thus,
(set-face-attribute 'foo nil :weight 'bold :slant 'italic)
sets the attribute :weight to bold and the attribute
:slant to italic.
If frame is t, this function sets the default attributes
for newly created frames; they will effectively override the attribute
values specified by defface. If frame is nil,
this function sets the attributes for all existing frames, as well as
for newly created frames.
To reset the value of an attribute, that is, to indicate that
the face doesn’t by itself specify a value for the attribute, use the
special value unspecified (not nil!) for the
attribute, and set the frame argument to t, in addition
to the call with frame set to nil. This is because the
default attributes for newly created frames are merged with the face’s
spec in defface when a new frame is created, and so having
unspecified in the default attributes for new frames will be
unable to override defface; the special call to this function
as described above will arrange for defface to be overridden.
Note that the attribute-value pairs are evaluated in the order they
are specified, with the exception of the :family and
:foundry attributes, which are evaluated first. This means
that if a certain attribute is specified more than once, only the last
value will be used. It also means that in some cases a different
order of attributes will produce different results. For example, when
:weight is placed before :font, the weight value is
applied to the current font of the face, and might be rounded to the
closest available weight of that font, whereas when :font is
placed before :weight the weight value is applied to the
specified font.
The following commands and functions mostly provide compatibility
with old versions of Emacs. They work by calling
set-face-attribute. Values of t and nil (or
omitted) for their frame argument are handled just like
set-face-attribute and face-attribute. The commands
read their arguments using the minibuffer, if called interactively.
These set the :foreground attribute (or :background
attribute, respectively) of face to color.
This sets the :stipple attribute of face to
pattern.
Change the font-related attributes of face to those of
font (a string or a font object). See face-font-attribute,
for the supported formats of the font argument. This function
sets the attribute :font of the face, and indirectly also the
:family, :foundry, :width, :height,
:weight, and :slant attributes, as defined by the font.
If frame is non-nil, only change the attributes on the
specified frame.
This sets the :weight attribute of face to normal
if bold-p is nil, and to bold otherwise.
This sets the :slant attribute of face to normal if
italic-p is nil, and to italic otherwise.
This sets the :underline attribute of face to
underline.
This sets the :inverse-video attribute of face to
inverse-video-p.
This swaps the foreground and background colors of face face.
This sets the :extend attribute of face to
extend.
The following functions examine the attributes of a face. They
mostly provide compatibility with old versions of Emacs. If you don’t
specify frame, they refer to the selected frame; t refers
to the default data for new frames. They return unspecified if
the face doesn’t define any value for that attribute. If
inherit is nil, only an attribute directly defined by the
face is returned. If inherit is non-nil, any faces
specified by its :inherit attribute are considered as well, and
if inherit is a face or a list of faces, then they are also
considered, until a specified attribute is found. To ensure that the
return value is always specified, use a value of default for
inherit.
This function returns the name of the font used by the specified face.
If the optional argument frame is specified, it returns the name
of the font of face for that frame; frame defaults to the
selected frame if it is nil or omitted. If frame is
t, the function reports on the font defaults for face to
be used for new frames.
By default, the returned font is for displaying ASCII characters, but
if frame is anything but t, and the optional third
argument character is supplied, the function returns the font
name used by face for that character.
These functions return the foreground color (or background color,
respectively) of face face, as a string. If the color is
unspecified, they return nil.
This function returns the name of the background stipple pattern of face
face, or nil if it doesn’t have one.
This function returns a non-nil value if the :weight
attribute of face is bolder than normal (i.e., one of
semi-bold, bold, extra-bold, or
ultra-bold). Otherwise, it returns nil.
This function returns a non-nil value if the :slant
attribute of face is italic or oblique, and
nil otherwise.
This function returns non-nil if face face specifies
a non-nil :underline attribute.
This function returns non-nil if face face specifies
a non-nil :inverse-video attribute.
This function returns non-nil if face face specifies
a non-nil :extend attribute. The inherit argument
is passed to face-attribute.
When Emacs displays a given piece of text, the visual appearance of the text may be determined by faces drawn from different sources. If these various sources together specify more than one face for a particular character, Emacs merges the attributes of the various faces. Here is the order in which Emacs merges the faces, from highest to lowest priority:
region face. See Standard Faces in The GNU Emacs
Manual.
nil face
property, Emacs applies the face(s) specified by that property. If
the overlay has a mouse-face property and the mouse is near
enough to the overlay, Emacs applies the face or face attributes
specified by the mouse-face property instead. See Overlay Properties.
When multiple overlays cover the same character, an overlay with higher priority overrides those with lower priority. See Overlays.
face or mouse-face property,
Emacs applies the specified faces and face attributes. See Properties with Special Meanings. (This is how Font Lock mode faces are applied.
See Font Lock Mode.)
mode-line face. For the mode line of a
non-selected window, Emacs applies the mode-line-inactive face.
For a header line, Emacs applies the header-line face.
For a tab line, Emacs applies the tab-line face.
before-string or
after-string properties (see Overlay Properties), or from a
display string (see Other Display Specifications), and the string doesn’t
contain a face or mouse-face property, or these
properties leave some face attributes undefined, but the buffer text
affected by the overlay/display property does define a face or those
attributes, Emacs applies the face attributes of the “underlying”
buffer text. Note that this is so even if the overlay or display
string is displayed in the display margins (see Displaying in the Margins).
default face.
At each stage, if a face has a valid :inherit attribute,
Emacs treats any attribute with an unspecified value as having
the corresponding value drawn from the parent face(s). see Face Attributes. Note that the parent face(s) may also leave the
attribute unspecified; in that case, the attribute remains unspecified
at the next level of face merging.
The variable face-remapping-alist is used for buffer-local or
global changes in the appearance of a face. For instance, it is used
to implement the text-scale-adjust command (see Text
Scale in The GNU Emacs Manual).
The value of this variable is an alist whose elements have the form
(face . remapping). This causes Emacs to display
any text having the face face with remapping, rather than
the ordinary definition of face.
remapping may be any face spec suitable for a face text
property: either a face (i.e., a face name or a property list of
attribute/value pairs), or a list of faces. For details, see the
description of the face text property in Properties with Special Meanings. remapping serves as the complete specification for
the remapped face—it replaces the normal definition of face,
instead of modifying it.
If face-remapping-alist is buffer-local, its local value takes
effect only within that buffer. If face-remapping-alist
includes faces applicable only to certain windows, by using the
(:filtered (:window param val) spec),
that face takes effect only in windows that match the filter
conditions (see Properties with Special Meanings). To turn off face filtering
temporarily, bind face-filters-always-match to a non-nil
value, then all face filters will match any window.
Note: face remapping is non-recursive. If remapping references
the same face name face, either directly or via the
:inherit attribute of some other face in remapping, that
reference uses the normal definition of face. For instance, if
the mode-line face is remapped using this entry in
face-remapping-alist:
(mode-line italic mode-line)
then the new definition of the mode-line face inherits from the
italic face, and the normal (non-remapped) definition of
mode-line face.
The following functions implement a higher-level interface to
face-remapping-alist. Most Lisp code should use these
functions instead of setting face-remapping-alist directly, to
avoid trampling on remappings applied elsewhere. These functions are
intended for buffer-local remappings, so they all make
face-remapping-alist buffer-local as a side-effect. They manage
face-remapping-alist entries of the form
(face relative-spec-1 relative-spec-2 ... base-spec)
where, as explained above, each of the relative-spec-N and
base-spec is either a face name, or a property list of
attribute/value pairs. Each of the relative remapping entries,
relative-spec-N, is managed by the
face-remap-add-relative and face-remap-remove-relative
functions; these are intended for simple modifications like changing
the text size. The base remapping entry, base-spec, has
the lowest priority and is managed by the face-remap-set-base
and face-remap-reset-base functions; it is intended for major
modes to remap faces in the buffers they control.
This function adds specs as relative remappings for face face in the current buffer. specs should be a list where each element is either a face name, or a property list of attribute/value pairs.
The return value is a Lisp object that serves as a cookie; you can
pass this object as an argument to face-remap-remove-relative
if you need to remove the remapping later.
;; Remap the 'escape-glyph' face into a combination ;; of the 'highlight' and 'italic' faces: (face-remap-add-relative 'escape-glyph 'highlight 'italic) ;; Increase the size of the 'default' face by 50%: (face-remap-add-relative 'default :height 1.5)
Note that buffer-local face remapping does not work reliably for
parent faces of basic faces (see Basic Faces). (These are the
faces that are used in mode lines, header lines, and other basic
decorations of windows and frames.) For instance,
mode-line-inactive inherits from mode-line, but
remapping mode-line won’t normally have the desired effect on
mode-line-inactive, especially if done locally for some
buffers. Instead you have to remap mode-line-inactive
directly.
This function removes a relative remapping previously added by
face-remap-add-relative. cookie should be the Lisp
object returned by face-remap-add-relative when the remapping
was added.
This function sets the base remapping of face in the current
buffer to specs. If specs is empty, the default base
remapping is restored, similar to calling face-remap-reset-base
(see below); note that this is different from specs containing a
single value nil, which has the opposite result (the global
definition of face is ignored).
This overwrites the default base-spec, which inherits the global face definition, so it is up to the caller to add such inheritance if so desired.
This function sets the base remapping of face to its default value, which inherits from face’s global definition.
Here are additional functions for creating and working with faces.
This function returns a list of all defined face names.
This function returns the face number of face face. This
is a number that uniquely identifies a face at low levels within
Emacs. It is seldom necessary to refer to a face by its face number.
However, functions that manipulate glyphs, such as
make-glyph-code and glyph-face (see Glyphs) access
the face numbers internally. Note that the face number is stored as
the value of the face property of the face symbol, so we
recommend not to set that property of a face to any value of your own.
This function returns the documentation string of face face, or
nil if none was specified for it.
This returns t if the faces face1 and face2 have the
same attributes for display.
This returns non-nil if the face face displays
differently from the default face.
A face alias provides an equivalent name for a face. You can
define a face alias by giving the alias symbol the face-alias
property, with a value of the target face name. The following example
makes modeline an alias for the mode-line face.
(put 'modeline 'face-alias 'mode-line)
This macro defines obsolete-face as an alias for
current-face, and also marks it as obsolete, indicating that it
may be removed in future. when should be a string indicating
when obsolete-face was made obsolete (usually a version number
string).
This hook is used for automatically assigning faces to text in the buffer. It is part of the implementation of Jit-Lock mode, used by Font-Lock.
This variable holds a list of functions that are called by Emacs
redisplay as needed, just before doing redisplay. They are called even
when Font Lock Mode isn’t enabled. When Font Lock Mode is enabled, this
variable usually holds just one function, jit-lock-function.
The functions are called in the order listed, with one argument, a buffer position pos. Collectively they should attempt to assign faces to the text in the current buffer starting at pos.
The functions should record the faces they assign by setting the
face property. They should also add a non-nil
fontified property to all the text they have assigned faces to.
That property tells redisplay that faces have been assigned to that text
already.
It is probably a good idea for the functions to do nothing if the
character after pos already has a non-nil fontified
property, but this is not required. If one function overrides the
assignments made by a previous one, the properties after the last
function finishes are the ones that really matter.
For efficiency, we recommend writing these functions so that they usually assign faces to around 400 to 600 characters at each call.
Note that, when the buffer text includes very long lines, these
functions are called as if they were in a with-restriction form
(see Narrowing), with a
long-line-optimizations-in-fontification-functions label and
with the buffer narrowed to a portion around pos.
If your Emacs Lisp program needs to assign some faces to text, it is often a good idea to use certain existing faces or inherit from them, rather than defining entirely new faces. This way, if other users have customized those existing faces to give Emacs a certain look, your program will fit in without additional customization.
Some of the basic faces defined in Emacs are listed below. In addition to these, you might want to make use of the Font Lock faces for syntactic highlighting, if highlighting is not already handled by Font Lock mode, or if some Font Lock faces are not in use. See 字体锁定专用外观.
defaultThe default face, whose attributes are all specified. All other faces implicitly inherit from it: any unspecified attribute defaults to the attribute on this face (see Face Attributes).
mode-line-activemode-line-inactiveheader-linetab-lineBasic faces used for the mode line, header line, and tab line.
tool-bartab-barfringescroll-barwindow-dividerborderchild-frame-borderBasic faces used for the corresponding decorations of GUI frames.
cursorThe basic face used for the text cursor.
mouseThe basic face used for displaying mouse-sensitive text when the mouse pointer is on that text.
bolditalicbold-italicunderlinefixed-pitchfixed-pitch-serifvariable-pitchThese have the attributes indicated by their names (e.g., bold
has a bold :weight attribute), with all other attributes
unspecified (and so given by default).
shadowFor dimmed-out text. For example, it is used for the ignored part of a filename in the minibuffer (see Minibuffers for File Names in The GNU Emacs Manual).
linklink-visitedFor clickable text buttons that send the user to a different buffer or location.
highlightFor stretches of text that should temporarily stand out. For example,
it is commonly assigned to the mouse-face property for cursor
highlighting (see Properties with Special Meanings).
matchisearchlazy-highlightFor text matching (respectively) permanent search matches, interactive search matches, and lazy highlighting other matches than the current interactive one.
errorwarningsuccessFor text concerning errors, warnings, or successes. For example, these are used for messages in *Compilation* buffers.
Before Emacs can draw a character on a graphical display, it must
select a font for that character31. See Fonts in The GNU Emacs Manual. Normally,
Emacs automatically chooses a font based on the faces assigned to that
character—specifically, the face attributes :family,
:weight, :slant, and :width (see Face Attributes). The choice of font also depends on the character to be
displayed; some fonts can only display a limited set of characters.
If no available font exactly fits the requirements, Emacs looks for
the closest matching font. The variables in this section
control how Emacs makes this selection.
If a given family is specified but does not exist, this variable specifies alternative font families to try. Each element should have this form:
(family alternate-families...)
If family is specified but not available, Emacs will try the other families given in alternate-families, one by one, until it finds a family that does exist.
If there is no font that exactly matches all desired face attributes
(:width, :height, :weight, and :slant),
this variable specifies the order in which these attributes should be
considered when selecting the closest matching font. The value should
be a list containing those four attribute symbols, in order of
decreasing importance. The default is (:width :height :weight
:slant).
Font selection first finds the best available matches for the first attribute in the list; then, among the fonts which are best in that way, it searches for the best matches in the second attribute, and so on.
The attributes :weight and :width have symbolic values in
a range centered around normal. Matches that are more extreme
(farther from normal) are somewhat preferred to matches that are
less extreme (closer to normal); this is designed to ensure that
non-normal faces contrast with normal ones, whenever possible.
One example of a case where this variable makes a difference is when the
default font has no italic equivalent. With the default ordering, the
italic face will use a non-italic font that is similar to the
default one. But if you put :slant before :height, the
italic face will use an italic font, even if its height is not
quite right.
This variable lets you specify alternative font registries to try, if a given registry is specified and doesn’t exist. Each element should have this form:
(registry alternate-registries...)
If registry is specified but not available, Emacs will try the other registries given in alternate-registries, one by one, until it finds a registry that does exist.
Emacs can make use of scalable fonts, but by default it does not use them.
This variable controls which scalable fonts to use. A value of
nil, the default, means do not use scalable fonts. t
means to use any scalable font that seems appropriate for the text.
Otherwise, the value must be a list of regular expressions. Then a scalable font is enabled for use if its name matches any regular expression in the list. For example,
(setq scalable-fonts-allowed '("iso10646-1$"))
allows the use of scalable fonts with registry iso10646-1.
This variable specifies scaling for certain faces. Its value should be a list of elements of the form
(fontname-regexp . scale-factor)
If fontname-regexp matches the font name that is about to be used, this says to choose a larger similar font according to the factor scale-factor. You would use this feature to normalize the font size if certain fonts are bigger or smaller than their nominal heights and widths would suggest.
This function returns a list of available font names that match name. name should be a string containing a font name in either the Fontconfig, GTK+, or XLFD format (see Fonts in The GNU Emacs Manual). Within an XLFD string, wildcard characters may be used: the ‘*’ character matches any substring, and the ‘?’ character matches any single character. Case is ignored when matching font names.
If the optional arguments reference-face and frame are specified, the returned list includes only fonts that are the same size as reference-face (a face name) currently is on the frame frame.
The optional argument maximum sets a limit on how many fonts to
return. If it is non-nil, then the return value is truncated
after the first maximum matching fonts. Specifying a small
value for maximum can make this function much faster, in cases
where many fonts match the pattern.
The optional argument width specifies a desired font width. If
it is non-nil, the function only returns those fonts whose
characters are (on average) width times as wide as
reference-face.
This function returns a list describing the available fonts for family
family on frame. If family is omitted or nil,
this list applies to all families, and therefore, it contains all
available fonts. Otherwise, family must be a string; it may
contain the wildcards ‘?’ and ‘*’.
The list describes the display that frame is on; if frame is
omitted or nil, it applies to the selected frame’s display
(see Input Focus).
Each element in the list is a vector of the following form:
[family width point-size weight slant fixed-p full registry-and-encoding]
The first five elements correspond to face attributes; if you specify these attributes for a face, it will use this font.
The last three elements give additional information about the font.
fixed-p is non-nil if the font is fixed-pitch.
full is the full name of the font, and
registry-and-encoding is a string giving the registry and
encoding of the font.
A fontset is a list of fonts, each assigned to a range of character codes. An individual font cannot display the whole range of characters that Emacs supports, but a fontset can. Fontsets have names, just as fonts do, and you can use a fontset name in place of a font name when you specify the font for a frame or a face. Here is information about defining a fontset under Lisp program control.
This function defines a new fontset according to the specification string fontset-spec. The string should have this format:
fontpattern, [charset:font]...
Whitespace characters before and after the commas are ignored.
The first part of the string, fontpattern, should have the form of a standard X font name, except that the last two fields should be ‘fontset-alias’.
The new fontset has two names, one long and one short. The long name is
fontpattern in its entirety. The short name is
‘fontset-alias’. You can refer to the fontset by either
name. If a fontset with the same name already exists, an error is
signaled, unless noerror is non-nil, in which case this
function does nothing.
If optional argument style-variant-p is non-nil, that says
to create bold, italic and bold-italic variants of the fontset as well.
These variant fontsets do not have a short name, only a long one, which
is made by altering fontpattern to indicate the bold and/or italic
status.
The specification string also says which fonts to use in the fontset. See below for the details.
The construct ‘charset:font’ specifies which font to use (in this fontset) for one particular character set. Here, charset is the name of a character set, and font is the font to use for that character set. You can use this construct any number of times in the specification string.
For the remaining character sets, those that you don’t specify explicitly, Emacs chooses a font based on fontpattern: it replaces ‘fontset-alias’ with a value that names one character set. For the ASCII character set, ‘fontset-alias’ is replaced with ‘ISO8859-1’.
In addition, when several consecutive fields are wildcards, Emacs collapses them into a single wildcard. This is to prevent use of auto-scaled fonts. Fonts made by scaling larger fonts are not usable for editing, and scaling a smaller font is not useful because it is better to use the smaller font in its own size, which Emacs does.
Thus if fontpattern is this,
-*-fixed-medium-r-normal-*-24-*-*-*-*-*-fontset-24
the font specification for ASCII characters would be this:
-*-fixed-medium-r-normal-*-24-*-ISO8859-1
and the font specification for Chinese GB2312 characters would be this:
-*-fixed-medium-r-normal-*-24-*-gb2312*-*
You may not have any Chinese font matching the above font specification. Most X distributions include only Chinese fonts that have ‘song ti’ or ‘fangsong ti’ in the family field. In such a case, ‘Fontset-n’ can be specified as below:
Emacs.Fontset-0: -*-fixed-medium-r-normal-*-24-*-*-*-*-*-fontset-24,\
chinese-gb2312:-*-*-medium-r-normal-*-24-*-gb2312*-*
Then, the font specifications for all but Chinese GB2312 characters have ‘fixed’ in the family field, and the font specification for Chinese GB2312 characters has a wild card ‘*’ in the family field.
This function modifies the existing fontset to use the font specified by font-spec for displaying the specified characters.
If fontset is nil, this function modifies the fontset of
the selected frame or that of frame if frame is not
nil.
If fontset is t, this function modifies the default
fontset, whose short name as a string is ‘fontset-default’.
The characters argument can be a single character which should
be displayed using font-spec. It can also be a cons cell
(from . to), where from and to are
characters. In that case, use font-spec for all the characters
in the range from and to (inclusive).
characters may be a charset symbol (see Character Sets). In that case, use font-spec for all the characters in the charset.
characters may be a script symbol (see char-script-table). In that case, use font-spec for all the
characters belonging to the script. See also
use-default-font-for-symbols, which affects font selection
when characters specify or belong to the symbol script
(which includes symbol and punctuation characters).
characters may be nil, which means to use font-spec
for any character in fontset for which no font-spec is
specified.
font-spec may be a font-spec object created by the function
font-spec (see Low-Level Font Representation).
font-spec may be a cons cell (family . registry), where family is a family name of a font
(possibly including a foundry name at the head), and registry is
a registry name of a font (possibly including an encoding name at the
tail).
font-spec may be a font name, a string.
font-spec may be nil, which explicitly specifies that
there’s no font for the specified characters. This is useful,
for example, to avoid expensive system-wide search for fonts for
characters that have no glyphs, like those from the Unicode Private
Use Area (PUA).
The optional argument add, if non-nil, specifies how to
add font-spec to the font specifications previously set for
characters. If it is prepend, font-spec is
prepended to the existing specs. If it is append,
font-spec is appended. By default, font-spec overwrites
the previously set font specs.
For instance, this changes the default fontset to use a font whose
family name is ‘Kochi Gothic’ for all characters belonging to
the charset japanese-jisx0208:
(set-fontset-font t 'japanese-jisx0208
(font-spec :family "Kochi Gothic"))
Note that this function should generally be called from the user’s init files, and more generally before any of characters were displayed in the current Emacs session. That’s because for some scripts, Emacs caches the way they are displayed, and the cached information includes the font used for them – once these characters are displayed once, the cached font will continue to be used regardless of changes in the fontsets.
This function returns non-nil if Emacs ought to be able to
display char. Or more precisely, if the selected frame’s fontset
has a font to display the character set that char belongs to.
Fontsets can specify a font on a per-character basis; when the fontset does that, this function’s value may not be accurate.
This function may return non-nil even when there is no font
available, since it also checks whether the coding system for the text
terminal can encode the character (see Terminal I/O Encoding).
Normally, it is not necessary to manipulate fonts directly. In case you need to do so, this section explains how.
In Emacs Lisp, fonts are represented using three different Lisp object types: font objects, font specs, and font entities.
Return t if object is a font object, font spec, or font
entity. Otherwise, return nil.
The optional argument type, if non-nil, determines the
exact type of Lisp object to check for. In that case, type
should be one of font-object, font-spec, or
font-entity.
A font object is a Lisp object that represents a font that Emacs has opened. Font objects cannot be modified in Lisp, but they can be inspected.
Return the font object that is being used to display the character at
position position in the window window. If window
is nil, it defaults to the selected window. If string is
nil, position specifies a position in the current buffer;
otherwise, string should be a string, and position
specifies a position in that string.
A font spec is a Lisp object that contains a set of specifications that can be used to find a font. More than one font may match the specifications in a font spec.
Return a new font spec using the specifications in arguments,
which should come in property-value pairs. The possible
specifications are as follows:
:nameThe font name (a string), in either XLFD, Fontconfig, or GTK+ format. See Fonts in The GNU Emacs Manual.
:family:foundry:weight:slant:widthThese have the same meanings as the face attributes of the same name.
See Face Attributes. :family and :foundry are
strings, while the other three are symbols. As example values,
:slant may be italic, :weight may be bold
and :width may be normal.
:sizeThe font size—either a non-negative integer that specifies the pixel size, or a floating-point number that specifies the point size.
:adstyleAdditional typographic style information for the font, such as ‘sans’. The value should be a string or a symbol.
:registry ¶The charset registry and encoding of the font, such as ‘iso8859-1’. The value should be a string or a symbol.
:dpiThe resolution in dots per inch for which the font is designed. The value must be a non-negative number.
:spacingThe spacing of the font: proportional, dual, mono, or charcell. The
value should be either an integer (0 for proportional, 90 for dual,
100 for mono, 110 for charcell) or a one-letter symbol (one of
P, D, M, or C).
:avgwidthThe average width of the font in 1/10 pixel units. The value should be a non-negative number.
:scriptThe script that the font must support (a symbol).
:langThe language that the font should support. The value should be a symbol whose name is a two-letter ISO-639 language name. On X, the value is matched against the “Additional Style” field of the XLFD name of a font, if it is non-empty. On MS-Windows, fonts matching the spec are required to support codepages needed for the language. Currently, only a small set of CJK languages is supported with this property: ‘ja’, ‘ko’, and ‘zh’.
:otf ¶The font must be an OpenType font that supports these OpenType features, provided Emacs is compiled with a library, such as ‘libotf’ on GNU/Linux, that supports complex text layout for scripts which need that. The value must be a list of the form
(script-tag langsys-tag gsub gpos)
where script-tag is the OpenType script tag symbol;
langsys-tag is the OpenType language system tag symbol, or
nil to use the default language system; gsub is a list
of OpenType GSUB feature tag symbols, or nil if none is
required; and gpos is a list of OpenType GPOS feature tag
symbols, or nil if none is required. If gsub or
gpos is a list, a nil element in that list means that
the font must not match any of the remaining tag symbols. The
gpos element may be omitted. For the list of OpenType script,
language, and feature tags, see
the list of registered OTF tags.
:type ¶The symbol that specifies the font backend used to draw the
characters. The possible values depend on the platform and on how
Emacs was configured at build time. Typical values include
ftcrhb and xfthb on X, harfbuzz on MS-Windows,
ns on GNUstep, etc. It can also be nil if left
unspecified, typically in a font-spec.
Set the font property property in the font-spec font-spec to value. The property can any of the ones described above.
A font entity is a reference to a font that need not be open. Its properties are intermediate between a font object and a font spec: like a font object, and unlike a font spec, it refers to a single, specific font. Unlike a font object, creating a font entity does not load the contents of that font into computer memory. Emacs may open multiple font objects of different sizes from a single font entity referring to a scalable font.
This function returns a font entity that best matches the font spec
font-spec on frame frame. If frame is nil,
it defaults to the selected frame.
This function returns a list of all font entities that match the font spec font-spec.
The optional argument frame, if non-nil, specifies the
frame on which the fonts are to be displayed. The optional argument
num, if non-nil, should be an integer that specifies the
maximum length of the returned list. The optional argument
prefer, if non-nil, should be another font spec, which is
used to control the order of the returned list; the returned font
entities are sorted in order of decreasing closeness to that font
spec.
If you call set-face-attribute and pass a font spec, font
entity, or font name string as the value of the :font
attribute, Emacs opens the best matching font that is available
for display. It then stores the corresponding font object as the
actual value of the :font attribute for that face.
The following functions can be used to obtain information about a font. For these functions, the font argument can be a font object, a font entity, or a font spec.
This function returns the value of the font property property
for font. The property can any of the ones that
font-spec supports.
If font is a font spec and the font spec does not specify
property, the return value is nil. If font is a
font object or font entity, the value for the :script property
may be a list of scripts supported by the font, and the value of the
:otf property is a cons of the form (gsub . gpos), where gsub and gpos are lists
representing OpenType features supported by the font, of the form
((script-tag (langsys-tag feature...) ...) ...)
where script-tag, langsys-tag, and feature are symbols representing OpenType layout tags.
If font is a font object, the special property
:combining-capability is non-nil if the font backend of
font supports rendering of combining characters for non-OpenType
fonts.
This function returns a list of face attributes corresponding to
font. The optional argument frame specifies the frame on
which the font is to be displayed. If it is nil, the selected
frame is used. The return value has the form
(:family family :height height :weight weight :slant slant :width width)
where the values of family, height, weight, slant, and width are face attribute values. Some of these key-attribute pairs may be omitted from the list if they are not specified by font.
This function returns the XLFD (X Logical Font Descriptor), a string, matching font. See Fonts in The GNU Emacs Manual, for information about XLFDs.
If the optional argument fold-wildcards is non-nil,
consecutive wildcards in the XLFD are folded into one.
If the optional argument long-xlfds is omitted or nil,
then the function returns nil if the XLFD would exceed 255
characters in length; this is for compatibility with the X protocol,
which mandates that XLFDs are restricted to that length. If
long-xlfds is non-nil, this restriction is lifted, and
the function can return XLFDs of any length.
The following two functions return important information about a font.
This function returns information about a font specified by its
name, a string, as it is used on frame. If frame is
omitted or nil, it defaults to the selected frame.
The value returned by the function is a vector of the form
[opened-name full-name size height
baseline-offset relative-compose default-ascent
max-width ascent descent space-width
average-width filename capability]. Here’s the
description of each components of this vector:
The name used to open the font, a string.
The full name of the font, a string.
The pixel size of the font.
The height of the font in pixels.
The offset in pixels from the ASCII baseline, positive upward.
Numbers controlling how to compose characters.
The maximum advance width of the font.
The ascent and descent of this font. The sum of these two numbers should be equal to the value of height above.
The width, in pixels, of the font’s space character.
The average width of the font characters. Emacs uses this for calculating text layout on display; if the value of average-width is zero, Emacs uses the value of space-width instead for those purposes.
The file name of the font as a string. This can be nil if the
font back-end does not provide a way to find out the font’s file name.
A list whose first element is a symbol representing the font type, one
of x, opentype, truetype, type1,
pcf, or bdf. For OpenType fonts, the list includes 2
additional elements describing the GSUB and GPOS features
supported by the font. Each of these elements is a list of the form
((script (langsys feature …) …)
…), where script is a symbol representing an OpenType
script tag, langsys is a symbol representing an OpenType langsys
tag (or nil, which stands for the default langsys), and each
feature is a symbol representing an OpenType feature tag.
This function returns information about a font-object. (This is
in contrast to font-info, which takes the font name, a string,
as its argument.)
The value returned by the function is a vector of the form
[name filename pixel-size max-width
ascent descent space-width average-width
capability]. Here’s the description of each components of this
vector:
The font name, a string.
The file name of the font as a string. This can be nil if the
font back-end does not provide a way to find out the font’s file name.
The pixel size of the font used to open the font.
The maximum advance width of the font.
The ascent and descent of this font. The sum of these two numbers gives the font height.
The width, in pixels, of the font’s space character.
The average width of the font characters. If this is zero, Emacs uses the value of space-width instead, when it calculates text layout on display.
A list whose first element is a symbol representing the font type, one
of x, opentype, truetype, type1,
pcf, or bdf. For OpenType fonts, the list includes 2
additional elements describing the GSUB and GPOS features
supported by the font. Each of these elements is a list of the form
((script (langsys feature …) …)
…), where script is a symbol representing an OpenType
script tag, langsys is a symbol representing an OpenType langsys
tag (or nil, which stands for the default langsys), and each
feature is a symbol representing an OpenType feature tag.
The following four functions return size information about fonts used by various faces, allowing various layout considerations in Lisp programs. These functions take face remapping into consideration, returning information about the remapped face, if the face in question was remapped. See Face Remapping.
This function returns the average width in pixels of the font used by the current buffer’s default face, as that face is defined for the selected frame.
This function returns the height in pixels of the font used by the current buffer’s default face, as that face is defined for the selected frame.
This function returns the average width in pixels for the font used by
face in window. The specified window must be a live
window. If nil or omitted, window defaults to the
selected window, and face defaults to the default face in
window.
This function returns the height in pixels for the font used by
face in window. The specified window must be a live
window. If nil or omitted, window defaults to the
selected window, and face defaults to the default face in
window.
On graphical displays, Emacs draws fringes next to each window: thin vertical strips down the sides which can display bitmaps indicating truncation, continuation, horizontal scrolling, and so on.
The following buffer-local variables control the position and width of fringes in windows showing that buffer.
The fringes normally appear between the display margins and the window
text. If the value is non-nil, they appear outside the display
margins. See Displaying in the Margins.
This variable, if non-nil, specifies the width of the left
fringe in pixels. A value of nil means to use the left fringe
width from the window’s frame.
This variable, if non-nil, specifies the width of the right
fringe in pixels. A value of nil means to use the right fringe
width from the window’s frame.
Any buffer which does not specify values for these variables uses
the values specified by the left-fringe and right-fringe
frame parameters (see Layout Parameters).
The above variables actually take effect via the function
set-window-buffer (see Buffers and Windows), which calls
set-window-fringes as a subroutine. If you change one of these
variables, the fringe display is not updated in existing windows
showing the buffer, unless you call set-window-buffer again in
each affected window. You can also use set-window-fringes to
control the fringe display in individual windows.
This function sets the fringe widths of window window.
If window is nil, the selected window is used.
The argument left specifies the width in pixels of the left
fringe, and likewise right for the right fringe. A value of
nil for either one stands for the default width. If
outside-margins is non-nil, that specifies that fringes
should appear outside of the display margins.
If window is not large enough to accommodate fringes of the desired width, this leaves the fringes of window unchanged.
The values specified here may be later overridden by invoking
set-window-buffer (see Buffers and Windows) on window
with its keep-margins argument nil or omitted. However,
if the optional fifth argument persistent is non-nil and
the other arguments are processed successfully, the values specified
here unconditionally survive subsequent invocations of
set-window-buffer. This can be used to permanently turn off
fringes in the minibuffer window, consult the description of
set-window-scroll-bars for an example (see Scroll Bars).
This function returns information about the fringes of a window
window. If window is omitted or nil, the selected
window is used. The value has the form (left-width
right-width outside-margins persistent).
Fringe indicators are tiny icons displayed in the window fringe to indicate truncated or continued lines, buffer boundaries, etc.
When this is non-nil, Emacs displays a special glyph in the
fringe of each empty line at the end of the buffer, on graphical
displays. See Fringes. This variable is automatically
buffer-local in every buffer.
This buffer-local variable controls how the buffer boundaries and window scrolling are indicated in the window fringes.
Emacs can indicate the buffer boundaries—that is, the first and last line in the buffer—with angle icons when they appear on the screen. In addition, Emacs can display an up-arrow in the fringe to show that there is text above the screen, and a down-arrow to show there is text below the screen.
There are three kinds of basic values:
nilDon’t display any of these fringe icons.
leftDisplay the angle icons and arrows in the left fringe.
rightDisplay the angle icons and arrows in the right fringe.
Display the angle icons in the left fringe and don’t display the arrows.
Otherwise the value should be an alist that specifies which fringe
indicators to display and where. Each element of the alist should
have the form (indicator . position). Here,
indicator is one of top, bottom, up,
down, and t (which covers all the icons not yet
specified), while position is one of left, right
and nil.
For example, ((top . left) (t . right)) places the top angle
bitmap in left fringe, and the bottom angle bitmap as well as both
arrow bitmaps in right fringe. To show the angle bitmaps in the left
fringe, and no arrow bitmaps, use ((top . left) (bottom . left)).
This buffer-local variable specifies the mapping from logical fringe
indicators to the actual bitmaps displayed in the window fringes. The
value is an alist of elements (indicator
. bitmaps), where indicator specifies a logical indicator
type and bitmaps specifies the fringe bitmaps to use for that
indicator.
Each indicator should be one of the following symbols:
truncation, continuation.Used for truncation and continuation lines.
up, down, top, bottom, top-bottomUsed when indicate-buffer-boundaries is non-nil:
up and down indicate a buffer boundary lying above or
below the window edge; top and bottom indicate the
topmost and bottommost buffer text line; and top-bottom
indicates where there is just one line of text in the buffer.
empty-lineUsed to indicate empty lines after the buffer end when
indicate-empty-lines is non-nil.
overlay-arrowUsed for overlay arrows (see The Overlay Arrow).
Each bitmaps value may be a list of symbols (left
right [left1 right1]). The left and
right symbols specify the bitmaps shown in the left and/or right
fringe, for the specific indicator. left1 and right1 are
specific to the bottom and top-bottom indicators, and
are used to indicate that the last text line has no final newline.
Alternatively, bitmaps may be a single symbol which is used in
both left and right fringes.
See Fringe Bitmaps, for a list of standard bitmap symbols and how
to define your own. In addition, nil represents the empty
bitmap (i.e., an indicator that is not shown).
When fringe-indicator-alist has a buffer-local value, and
there is no bitmap defined for a logical indicator, or the bitmap is
t, the corresponding value from the default value of
fringe-indicator-alist is used.
When a line is exactly as wide as the window, Emacs displays the cursor in the right fringe instead of using two lines. Different bitmaps are used to represent the cursor in the fringe depending on the current buffer’s cursor type.
If this is non-nil, lines exactly as wide as the window (not
counting the final newline character) are not continued. Instead,
when point is at the end of the line, the cursor appears in the right
fringe.
This variable specifies the mapping from logical cursor type to the
actual fringe bitmaps displayed in the right fringe. The value is an
alist where each element has the form (cursor-type
. bitmap), which means to use the fringe bitmap bitmap to
display cursors of type cursor-type.
Each cursor-type should be one of box, hollow,
bar, hbar, or hollow-small. The first four have
the same meanings as in the cursor-type frame parameter
(see Cursor Parameters). The hollow-small type is used
instead of hollow when the normal hollow-rectangle
bitmap is too tall to fit on a specific display line.
Each bitmap should be a symbol specifying the fringe bitmap to be displayed for that logical cursor type. See Fringe Bitmaps.
When fringe-cursor-alist has a buffer-local value, and there is
no bitmap defined for a cursor type, the corresponding value from the
default value of fringes-indicator-alist is used.
The fringe bitmaps are the actual bitmaps which represent the
logical fringe indicators for truncated or continued lines, buffer
boundaries, overlay arrows, etc. Each bitmap is represented by a
symbol.
These symbols are referred to by the variable
fringe-indicator-alist, which maps fringe indicators to bitmaps
(see Fringe Indicators), and the variable
fringe-cursor-alist, which maps fringe cursors to bitmaps
(see Fringe Cursors).
Lisp programs can also directly display a bitmap in the left or
right fringe, by using a display property for one of the
characters appearing in the line (see Other Display Specifications). Such
a display specification has the form
(fringe bitmap [face])
fringe is either the symbol left-fringe or
right-fringe. bitmap is a symbol identifying the bitmap
to display. The optional face names a face whose foreground and
background colors are to be used to display the bitmap, using the
attributes of the fringe face for colors that face didn’t
specify. If face is omitted, that means to use the attributes
of the default face for the colors which the fringe face
didn’t specify. For predictable results that don’t depend on the
attributes of the default and fringe faces, we recommend
you never omit face, but always provide a specific face. In
particular, if you want the bitmap to be always displayed in the
fringe face, use fringe as face.
For instance, to display an arrow in the left fringe, using the
warning face, you could say something like:
(overlay-put
(make-overlay (point) (point))
'before-string (propertize
"x" 'display
`(left-fringe right-arrow warning)))
Here is a list of the standard fringe bitmaps defined in Emacs, and
how they are currently used in Emacs (via
fringe-indicator-alist and fringe-cursor-alist):
left-arrow, right-arrowUsed to indicate truncated lines.
left-curly-arrow, right-curly-arrowUsed to indicate continued lines.
right-triangle, left-triangleThe former is used by overlay arrows. The latter is unused.
up-arrow, down-arrowbottom-left-angle, bottom-right-angletop-left-angle, top-right-angleleft-bracket, right-bracketempty-lineUsed to indicate buffer boundaries.
filled-rectangle, hollow-rectanglefilled-square, hollow-squarevertical-bar, horizontal-barUsed for different types of fringe cursors.
exclamation-mark, question-marklarge-circleNot used by core Emacs features.
The next subsection describes how to define your own fringe bitmaps.
This function returns the fringe bitmaps of the display line
containing position pos in window window. The return
value has the form (left right ov), where left
is the symbol for the fringe bitmap in the left fringe (or nil
if no bitmap), right is similar for the right fringe, and ov
is non-nil if there is an overlay arrow in the left fringe.
The value is nil if pos is not visible in window.
If window is nil, that stands for the selected window.
If pos is nil, that stands for the value of point in
window.
This function defines the symbol bitmap as a new fringe bitmap, or replaces an existing bitmap with that name.
The argument bits specifies the image to use. It should be either a string or a vector of integers, where each element (an integer) corresponds to one row of the bitmap. Each bit of an integer corresponds to one pixel of the bitmap, where the low bit corresponds to the rightmost pixel of the bitmap. (Note that this order of bits is opposite of the order in XBM images; see XBM Images.)
The height is normally the length of bits. However, you
can specify a different height with non-nil height. The width
is normally 8, but you can specify a different width with non-nil
width. The width must be an integer between 1 and 16.
The argument align specifies the positioning of the bitmap
relative to the range of rows where it is used; the default is to
center the bitmap. The allowed values are top, center,
or bottom.
The align argument may also be a list (align
periodic) where align is interpreted as described above.
If periodic is non-nil, it specifies that the rows in
bits should be repeated enough times to reach the specified
height.
This function destroys the fringe bitmap identified by bitmap. If bitmap identifies a standard fringe bitmap, it actually restores the standard definition of that bitmap, instead of eliminating it entirely.
This sets the face for the fringe bitmap bitmap to face.
If face is nil, it selects the fringe face. The
bitmap’s face controls the color to draw it in.
face is merged with the fringe face, so normally
face should specify only the foreground color.
The overlay arrow is useful for directing the user’s attention to a particular line in a buffer. For example, in the modes used for interface to debuggers, the overlay arrow indicates the line of code about to be executed. This feature has nothing to do with overlays (see Overlays).
This variable holds the string to display to call attention to a
particular line, or nil if the arrow feature is not in use.
On a graphical display the contents of the string are ignored if the
left fringe is shown; instead a glyph is displayed in the fringe area
to the left of the display area.
This variable holds a marker that indicates where to display the overlay arrow. It should point at the beginning of a line. On a non-graphical display, or when the left fringe is not shown, the arrow text appears at the beginning of that line, overlaying any text that would otherwise appear. Since the arrow is usually short, and the line usually begins with indentation, normally nothing significant is overwritten.
The overlay-arrow string is displayed in any given buffer if the value
of overlay-arrow-position in that buffer points into that
buffer. Thus, it is possible to display multiple overlay arrow strings
by creating buffer-local bindings of overlay-arrow-position.
However, it is usually cleaner to use
overlay-arrow-variable-list to achieve this result.
You can do a similar job by creating an overlay with a
before-string property. See Overlay Properties.
You can define multiple overlay arrows via the variable
overlay-arrow-variable-list.
This variable’s value is a list of variables, each of which specifies
the position of an overlay arrow. The variable
overlay-arrow-position has its normal meaning because it is on
this list.
Each variable on this list can have properties
overlay-arrow-string and overlay-arrow-bitmap that
specify an overlay arrow string (for text terminals or graphical
terminals without the left fringe shown) or fringe bitmap
(for graphical terminals with a left fringe) to display at the
corresponding overlay arrow position. If either property is not set,
the default overlay-arrow-string or overlay-arrow fringe
indicator is used.
Normally the frame parameter vertical-scroll-bars controls
whether the windows in the frame have vertical scroll bars, and whether
they are on the left or right. The frame parameter
scroll-bar-width specifies how wide they are (nil meaning
the default).
The frame parameter horizontal-scroll-bars controls whether
the windows in the frame have horizontal scroll bars. The frame
parameter scroll-bar-height specifies how high they are
(nil meaning the default). See Layout Parameters.
Horizontal scroll bars are not available on all platforms. The
function horizontal-scroll-bars-available-p which takes no
argument returns non-nil if they are available on your system.
The following three functions take as argument a live frame which defaults to the selected one.
This function reports the scroll bar types for frame frame. The
value is a cons cell (vertical-type .
horizontal-type), where vertical-type is either
left, right, or nil (which means no vertical scroll
bar.) horizontal-type is either bottom or nil
(which means no horizontal scroll bar).
This function returns the width of vertical scroll bars of frame in pixels.
This function returns the height of horizontal scroll bars of frame in pixels.
You can override the frame specific settings for individual windows by using the following function:
This function sets the width and/or height and the types of scroll bars
for window window. If window is nil, the selected
window is used.
width specifies the width of the vertical scroll bar in pixels
(nil means use the width specified for the frame).
vertical-type specifies whether to have a vertical scroll bar and,
if so, where. The possible values are left, right,
t, which means to use the frame’s default, and nil for no
vertical scroll bar.
height specifies the height of the horizontal scroll bar in
pixels (nil means use the height specified for the frame).
horizontal-type specifies whether to have a horizontal scroll
bar. The possible values are bottom, t, which means to
use the frame’s default, and nil for no horizontal scroll bar.
Note that for a mini window the value t has the same meaning as
nil, namely to not show a horizontal scroll bar. You have to
explicitly specify bottom in order to show a horizontal scroll
bar in a mini window.
If window is not large enough to accommodate a scroll bar of the desired dimension, this leaves the corresponding scroll bar unchanged.
The values specified here may be later overridden by invoking
set-window-buffer (see Buffers and Windows) on window
with its keep-margins argument nil or omitted. However,
if the optional fifth argument persistent is non-nil and
the other arguments are processed successfully, the values specified
here unconditionally survive subsequent invocations of
set-window-buffer.
Using the persistent argument of set-window-scroll-bars
and set-window-fringes (see Fringe Size and Position) you can
reliably and permanently turn off scroll bars and/or fringes in any
minibuffer window by adding the following snippet to your early init
file (see The Init File).
(add-hook 'after-make-frame-functions
(lambda (frame)
(set-window-scroll-bars
(minibuffer-window frame) 0 nil 0 nil t)
(set-window-fringes
(minibuffer-window frame) 0 0 nil t)))
The following four functions take as argument a live window which defaults to the selected one.
This function returns a list of the form (width
columns vertical-type height lines
horizontal-type persistent).
The value width is the value that was specified for the width of
the vertical scroll bar (which may be nil); columns is the
(possibly rounded) number of columns that the vertical scroll bar
actually occupies.
The value height is the value that was specified for the height of
the horizontal scroll bar (which may be nil); lines is the
(possibly rounded) number of lines that the horizontally scroll bar
actually occupies.
The value of persistent is the value specified for window
with the last successful invocation of set-window-scroll-bars,
nil if there never was one.
This function reports the scroll bar type for window window. The
value is a cons cell (vertical-type .
horizontal-type). Unlike window-scroll-bars, this reports
the scroll bar type actually used, once frame defaults and
scroll-bar-mode are taken into account.
This function returns the width in pixels of window’s vertical scrollbar.
This function returns the height in pixels of window’s horizontal scrollbar.
If you do not specify a window’s scroll bar settings via
set-window-scroll-bars, the buffer-local variables
vertical-scroll-bar, horizontal-scroll-bar,
scroll-bar-width and scroll-bar-height in the buffer being
displayed control the window’s scroll bars. The function
set-window-buffer examines these variables. If you change them
in a buffer that is already visible in a window, you can make the window
take note of the new values by calling set-window-buffer
specifying the same buffer that is already displayed.
You can control the appearance of scroll bars for a particular buffer by setting the following variables which automatically become buffer-local when set.
This variable specifies the location of the vertical scroll bar. The
possible values are left, right, t, which means to
use the frame’s default, and nil for no scroll bar.
This variable specifies the location of the horizontal scroll bar. The
possible values are bottom, t, which means to use the
frame’s default, and nil for no scroll bar.
This variable specifies the width of the buffer’s vertical scroll bars,
measured in pixels. A value of nil means to use the value
specified by the frame.
This variable specifies the height of the buffer’s horizontal scroll
bar, measured in pixels. A value of nil means to use the value
specified by the frame.
Finally you can toggle the display of scroll bars on all frames by
customizing the variables scroll-bar-mode and
horizontal-scroll-bar-mode.
This variable controls whether and where to put vertical scroll bars in
all frames. The possible values are nil for no scroll bars,
left to put scroll bars on the left and right to put
scroll bars on the right.
This variable controls whether to display horizontal scroll bars on all frames.
Window dividers are bars drawn between a frame’s windows. A right
divider is drawn between a window and any adjacent windows on the right.
Its width (thickness) is specified by the frame parameter
right-divider-width. A bottom divider is drawn between a
window and adjacent windows on the bottom or the echo area. Its width
is specified by the frame parameter bottom-divider-width. In
either case, specifying a width of zero means to not draw such dividers.
See Layout Parameters.
Technically, a right divider belongs to the window on its left, which means that its width contributes to the total width of that window. A bottom divider belongs to the window above it, which means that its width contributes to the total height of that window. See Window Sizes. When a window has both, a right and a bottom divider, the bottom divider prevails. This means that a bottom divider is drawn over the full total width of its window while the right divider ends above the bottom divider.
Dividers can be dragged with the mouse and are therefore useful for adjusting the sizes of adjacent windows with the mouse. They also serve to visually set apart adjacent windows when no scroll bars or mode lines are present. The following three faces allow the customization of the appearance of dividers:
window-dividerWhen a divider is less than three pixels wide, it is drawn solidly with the foreground of this face. For larger dividers this face is used for the inner part only, excluding the first and last pixel.
window-divider-first-pixelThis is the face used for drawing the first pixel of a divider that is
at least three pixels wide. To obtain a solid appearance, set this to
the same value used for the window-divider face.
window-divider-last-pixelThis is the face used for drawing the last pixel of a divider that is at
least three pixels wide. To obtain a solid appearance, set this to the
same value used for the window-divider face.
You can get the sizes of the dividers of a specific window with the following two functions.
Return the width (thickness) in pixels of window’s right divider. window must be a live window and defaults to the selected one. The return value is always zero for a rightmost window.
Return the width (thickness) in pixels of window’s bottom divider. window must be a live window and defaults to the selected one. The return value is zero for the minibuffer window or a bottommost window on a minibuffer-less frame.
display Property ¶The display text property (or overlay property) is used to
insert images into text, and to control other aspects of how text
displays. Display specifications in the same display
property value generally apply in parallel to the text they cover.
If several sources (overlays and/or a text property) specify values
for the display property, only one of the values takes effect,
following the rules of get-char-property. See Examining Text Properties.
The value of the display property should be a display
specification, or a list or vector containing several display
specifications.
This convenience function can be used to get a specific display
property, no matter whether the display property is a vector, a
list or a simple property. This is like get-text-property
(see Examining Text Properties), but works on the display
property only.
position is the position in the buffer or string to examine, and
prop is the display property to return. The optional
object argument should be either a string or a buffer, and
defaults to the current buffer. If the optional properties
argument is non-nil, it should be a display property,
and in that case, position and object are ignored. (This
can be useful if you’ve already gotten the display property
with get-char-property, for instance (see Examining Text Properties).
Add display property prop of value to the text from
start to end.
If any text in the region has a non-nil display
property, those properties are retained. For instance:
(add-display-text-property 4 8 'height 2.0) (add-display-text-property 2 12 'raise 0.5)
After doing this, the region from 2 to 4 will have the raise
display property, the region from 4 to 8 will have both the
raise and height display properties, and finally
the region from 8 to 12 will only have the raise display
property.
If object is non-nil, it should be a string or a buffer.
If nil, this defaults to the current buffer.
Some of the display specifications allow inclusion of Lisp forms,
which are evaluated at display time. This could be unsafe in certain
situations, e.g., when the display specification was generated by some
external program/agent. Wrapping a display specification in a list
that begins with the special symbol disable-eval, as in
(disable-eval spec), will disable evaluation of any
Lisp in spec, while still supporting all the other display
property features.
The rest of this section describes several kinds of display specifications and what they mean.
Some kinds of display specifications specify something to display instead of the text that has the property. These are called replacing display specifications. Emacs does not allow the user to interactively move point into the middle of buffer text that is replaced in this way.
If a list of display specifications includes more than one replacing
display specification, the first overrides the rest. Replacing
display specifications make most other display specifications
irrelevant, since those don’t apply to the replacement. In addition,
any invisible and composition properties of the text that
is replaced are ignored, because the replaced text is skipped and its
properties are not processed.
For replacing display specifications, the text that has the
property means all the consecutive characters that have the same
Lisp object as their display property; these characters are
replaced as a single unit. If two characters have different Lisp
objects as their display properties (i.e., objects which are
not eq), they are handled separately.
Here is an example which illustrates this point. A string serves as a replacing display specification, which replaces the text that has the property with the specified string (see Other Display Specifications). Consider the following function:
(defun foo ()
(dotimes (i 5)
(let ((string (concat "A"))
(start (+ i i (point-min))))
(put-text-property start (1+ start) 'display string)
(put-text-property start (+ 2 start) 'display string))))
This function gives each of the first ten characters in the buffer a
display property which is a string "A", but they don’t
all get the same string object. The first two characters get the same
string object, so they are replaced with one ‘A’; the fact that
the display property was assigned in two separate calls to
put-text-property is irrelevant. Similarly, the next two
characters get a second string (concat creates a new string
object), so they are replaced with one ‘A’; and so on. Thus, the
ten characters appear as five A’s.
Note: Using :box face attribute (see Face Attributes) on a
replacing display string that is adjacent to normal text with
the same :box style can lead to display artifacts when moving
the cursor across the text with this face attribute. These can be
avoided by applying the :box attribute directly to the text
being replaced, rather than (or in addition to) the display
string itself. Here’s an example:
;; Causes display artifacts when moving the cursor across text (progn (put-text-property 1 2 'display (propertize " [" 'face '(:box t))) (put-text-property 2 3 'face '(:box t)) (put-text-property 3 4 'display (propertize "] " 'face '(:box t))))
;; No display artifacts due to `:box' (progn (add-text-properties 1 2 '(face (:box t) display " [")) (put-text-property 2 3 'face '(:box t)) (add-text-properties 3 4 '(face (:box t) display "] ")))
To display a space of specified width and/or height, use a display
specification of the form (space . props), where
props is a property list (a list of alternating properties and
values). You can put this property on one or more consecutive
characters; a space of the specified height and width is displayed in
place of all of those characters. These are the properties you
can use in props to specify the weight of the space:
:width widthIf width is a number, it specifies that the space width should be width times the normal character width. width can also be a pixel width specification (see Pixel Specification for Spaces).
:relative-width factorSpecifies that the width of the stretch should be computed from the
first character in the group of consecutive characters that have the
same display property. The space width is the pixel width of
that character, multiplied by factor. (On text-mode terminals,
the “pixel width” of a character is usually 1, but it could be more
for TABs and double-width CJK characters.)
:align-to hposSpecifies that the space should be wide enough to reach the column
hpos. If hpos is a number, it is a column number, and is
measured in units of the canonical character width (see Frame Font). hpos can also be a pixel width specification
(see Pixel Specification for Spaces). When the current line is wider than
the window, and is either displayed by one or more continuation lines,
or is truncated and possibly scrolled horizontally (see Horizontal Scrolling), hpos is measured from the beginning of the logical
line, not from the visual beginning of the screen line. This way,
alignment produced by :align-to is consistent with functions
that count columns, such as current-column and
move-to-column (see Counting Columns). (There’s a single exception
from this rule: when :align-to is used to specify whitespace of
the wrap-prefix variable or text property, see Truncation.)
You should use one and only one of the above properties. You can also specify the height of the space, with these properties:
:height heightSpecifies the height of the space. If height is a number, it specifies that the space height should be height times the normal character height. The height may also be a pixel height specification (see Pixel Specification for Spaces).
:relative-height factorSpecifies the height of the space, multiplying the ordinary height of the text having this display specification by factor.
:ascent ascentIf the value of ascent is a non-negative number no greater than 100, it specifies that ascent percent of the height of the space should be considered as the ascent of the space—that is, the part above the baseline. The ascent may also be specified in pixel units with a pixel ascent specification (see Pixel Specification for Spaces).
Don’t use both :height and :relative-height together.
The :width and :align-to properties are supported on
non-graphic terminals, but the other space properties in this section
are not.
Note that space properties are treated as paragraph separators for the purposes of reordering bidirectional text for display. See Bidirectional Display, for the details.
The value of the :width, :align-to, :height,
and :ascent properties can be a special kind of expression that
is evaluated during redisplay. The result of the evaluation is used
as an absolute number of pixels.
The following expressions are supported:
expr ::= num | (num) | unit | elem | pos | image | xwidget | form num ::= integer | float | symbol unit ::= in | mm | cm | width | height
elem ::= left-fringe | right-fringe | left-margin | right-margin
| scroll-bar | text
pos ::= left | center | right
form ::= (num . expr) | (op expr ...)
op ::= + | -
The form num specifies a fraction of the default frame font
height or width. The form (num) specifies an absolute
number of pixels. If num is a symbol, symbol, its
buffer-local variable binding is used; that binding can be either a
number or a cons cell of the forms shown above (including yet another
cons cell whose car is a symbol that has a buffer-local
binding).
The in, mm, and cm units specify the number of
pixels per inch, millimeter, and centimeter, respectively. The
width and height units correspond to the default width
and height of the current face. An image specification of the form
(image . props) (see Image Descriptors)
corresponds to the width or height of the specified image. Similarly,
an xwidget specification of the form (xwidget . props)
stands for the width or height of the specified xwidget.
See Embedded Native Widgets.
The elements left-fringe, right-fringe,
left-margin, right-margin, scroll-bar, and
text specify the width of the corresponding area of the window.
When the window displays line numbers (see Size of Displayed Text), the width of the text area is decreased by the screen
space taken by the line-number display.
The left, center, and right positions can be
used with :align-to to specify a position relative to the left
edge, center, or right edge of the text area. When the window
displays line numbers, and :align-to is used in display
properties of buffer text (as opposed to header line, see below), the
left and the center positions are offset to account for
the screen space taken by the line-number display.
Any of the above window elements (except text) can also be
used with :align-to to specify that the position is relative to
the left edge of the given area. Once the base offset for a relative
position has been set (by the first occurrence of one of these
symbols), further occurrences of these symbols are interpreted as the
width of the specified area. For example, to align to the center of
the left-margin, use
:align-to (+ left-margin (0.5 . left-margin))
If no specific base offset is set for alignment, it is always relative to the left edge of the text area. For example, ‘:align-to 0’ aligns with the first text column in the text area. When the window displays line numbers, the text is considered to start where the space used for line-number display ends.
A value of the form (num . expr) stands for the
product of the values of num and expr. For example,
(2 . in) specifies a width of 2 inches, while (0.5 .
image) specifies half the width (or height) of the specified
image (which should be given by its image spec).
The form (+ expr ...) adds up the value of the
expressions. The form (- expr ...) negates or subtracts
the value of the expressions.
Text shown in the header line that uses :align-to display
specifications is not automatically realigned when
display-line-numbers-mode is turned on and off, or when the
width of line numbers on display changes. To arrange for the
header-line text alignment to be updated, thus keeping the header-line
text aligned with the buffer text, turn on the
header-line-indent-mode in the buffer and use its two
variables, header-line-indent and
header-line-indent-width, in the display specification.
See 窗口标题栏. Here’s a simple example:
(setq header-line-format
(concat (propertize " "
'display
'(space :align-to
(+ header-line-indent-width 10)))
"Column"))
This will keep the text ‘Column’ on the header line aligned with
column 10 of buffer text, regardless of whether
display-line-numbers-mode is on or off, and also when
line-number display changes its width.
Here are the other sorts of display specifications that you can use
in the display text property.
stringDisplay string instead of the text that has this property.
Recursive display specifications are not supported—string’s
display properties, if any, are not used.
(image . image-props)This kind of display specification is an image descriptor (see Image Descriptors). When used as a display specification, it means to display the image instead of the text that has the display specification.
(slice x y width height)This specification together with image specifies a slice
(a partial area) of the image to display. More precisely, the
specification should have the following form:
((slice x y width height) image-desc)
where image-desc is an image descriptor described above. The elements x and y specify the top left corner of the slice, within the image; width and height specify the width and height of the slice. Integers are numbers of pixels. A floating-point number in the range 0.0–1.0 stands for that fraction of the width or height of the entire image.
((margin nil) string)A display specification of this form means to display string instead of the text that has the display specification, at the same position as that text. It is equivalent to using just string, but it is done as a special case of marginal display (see Displaying in the Margins).
(left-fringe bitmap [face])(right-fringe bitmap [face])This display specification on any character of a line of text causes the specified bitmap be displayed in the left or right fringes for that line, instead of the characters that have the display specification. The optional face specifies the face whose colors are to be used for the bitmap display. See Fringe Bitmaps, for the details.
It also possible to add context help for fringe bitmaps through the
show-help-function mechanism by using left-fringe-help and
right-fringe-help text properties (see Properties with Special Meanings).
(space-width factor)This display specification affects all the space characters within the text that has the specification. It displays all of these spaces factor times as wide as normal. The element factor should be an integer or float. Characters other than spaces are not affected at all; in particular, this has no effect on tab characters.
(min-width (width))This display specification ensures the text that has it takes at least width space on display, by adding a stretch of white space to the end of the text if the text is shorter than width. The text is partitioned using the identity of the parameter, which is why the parameter is a list with one element. For instance:
(insert (propertize "foo" 'display '(min-width (6.0))))
This will add padding after ‘foo’ bringing the total width up to
the width of six normal characters. Note that the affected characters
are identified by the (6.0) list in the display property,
compared with eq. The element width can be either an
integer or a float specifying the required minimum width of the text
(see Pixel Specification for Spaces).
(height height)This display specification makes the text taller or shorter. Here are the possibilities for height:
(+ n)This means to use a font that is n steps larger. A step is defined by the set of available fonts—specifically, those that match what was otherwise specified for this text, in all attributes except height. Each size for which a suitable font is available counts as another step. n should be an integer.
(- n)This means to use a font that is n steps smaller.
A number, factor, means to use a font that is factor times as tall as the default font.
A symbol is a function to compute the height. It is called with the current height as argument, and should return the new height to use.
If the height value doesn’t fit the previous possibilities, it is
a form. Emacs evaluates it to get the new height, with the symbol
height bound to the current specified font height.
(raise factor)This kind of display specification raises or lowers the text it applies to, relative to the baseline of the line. It is mainly meant to support display of subscripts and superscripts.
The factor must be a number, which is interpreted as a multiple of the height of the affected text. If it is positive, that means to display the characters raised. If it is negative, that means to display them lower down.
Note that if the text also has a height display specification,
which was specified before (i.e. to the left of) raise, the
latter will affect the amount of raising or lowering in pixels,
because that is based on the height of the text being raised.
Therefore, if you want to display a sub- or superscript that is
smaller than the normal text height, consider specifying raise
before height.
You can make any display specification conditional. To do that,
package it in another list of the form
(when condition . spec).
Then the specification spec applies only when
condition evaluates to a non-nil value. During the
evaluation, object is bound to the string or buffer having the
conditional display property. position and
buffer-position are bound to the position within object
and the buffer position where the display property was found,
respectively. Both positions can be different when object is a
string.
Note that condition will only be evaluated when redisplay examines the text where this display spec is located, so this feature is best suited for conditions that are relatively stable, i.e. yield, for each particular buffer position, the same results on every evaluation. If the results change for the same text location, e.g., if the result depends on the position of point, then the conditional specification might not do what you want, because redisplay examines only those parts of buffer text where it has reasons to assume that something changed since the last display cycle.
A buffer can have blank areas called display margins on the
left and on the right. Ordinary text never appears in these areas,
but you can put things into the display margins using the
display property. There is currently no way to make text or
images in the margin mouse-sensitive.
The way to display something in the margins is to specify it in a
margin display specification in the display property of some
text. This is a replacing display specification, meaning that the
text you put it on does not get displayed; the margin display appears,
but that text does not.
A margin display specification looks like ((margin
right-margin) spec) or ((margin left-margin) spec).
Here, spec is another display specification that says what to
display in the margin. Typically it is a string of text to display,
or an image descriptor.
To display something in the margin in association with
certain buffer text, without altering or preventing the display of
that text, put on that text an overlay with a before-string
property, and put the margin display specification on the contents of
the before-string.
Note that if the string to be displayed in the margin doesn’t specify a face, its face is determined using the same rules and priorities as it is for strings displayed in the text area (see Displaying Faces). If this results in undesirable “leaking” of faces into the margin, make sure the string has an explicit face specified for it.
Before the display margins can display anything, you must give them a nonzero width. The usual way to do that is to set these variables:
This variable specifies the width of the left margin, in character
cell (a.k.a. “column”) units. It is buffer-local in all buffers.
A value of nil means no left marginal area.
This variable specifies the width of the right margin, in character
cell units. It is buffer-local in all buffers. A value of nil
means no right marginal area.
Setting these variables does not immediately affect the window. These
variables are checked when a new buffer is displayed in the window.
Thus, you can make changes take effect by calling
set-window-buffer. Do not use these variables to try to
determine the current width of the left or right margin. Instead, use
the function window-margins.
You can also set the margin widths immediately.
This function specifies the margin widths for window window, in
character cell units. The argument left controls the left
margin, and right controls the right margin (default 0).
If window is not large enough to accommodate margins of the desired width, this leaves the margins of window unchanged.
The values specified here may be later overridden by invoking
set-window-buffer (see Buffers and Windows) on window
with its keep-margins argument nil or omitted.
This function returns the width of the left and right margins of
window as a cons cell of the form (left . right). If one of the two marginal areas does not exist,
its width is returned as nil; if neither of the two margins exist,
the function returns (nil). If window is nil, the
selected window is used.
To display an image in an Emacs buffer, you must first create an image
descriptor, then use it as a display specifier in the display
property of text that is displayed (see The display Property).
Emacs is usually able to display images when it is run on a
graphical terminal. Images cannot be displayed in a text terminal, on
certain graphical terminals that lack the support for this, or if
Emacs is compiled without image support. You can use the function
display-images-p to determine if images can in principle be
displayed (see Display Feature Testing).
Emacs can display a number of different image formats. Some of
these image formats are supported only if particular support libraries
are installed. On some platforms, Emacs can load support libraries on
demand; if so, the variable dynamic-library-alist can be used
to modify the set of known names for these dynamic libraries.
See Dynamically Loaded Libraries.
Supported image formats (and the required support libraries) include
PBM and XBM (which do not depend on support libraries and are always
available), XPM (libXpm), GIF (libgif or
libungif), JPEG (libjpeg), TIFF (libtiff), PNG
(libpng), SVG (librsvg), and WebP (libwebp).
Each of these image formats is associated with an image type
symbol. The symbols for the above formats are, respectively,
pbm, xbm, xpm, gif, jpeg,
tiff, png, svg, and webp.
On some platforms, the built-in image support that doesn’t require any optional libraries includes BMP images.32
Furthermore, if you build Emacs with ImageMagick
(libMagickWand) support, Emacs can display any image format
that ImageMagick can. See ImageMagick Images. All images
displayed via ImageMagick have type symbol imagemagick.
This variable contains a list of type symbols for image formats which are potentially supported in the current configuration.
“Potentially” means that Emacs knows about the image types, not
necessarily that they can be used (for example, they could depend on
unavailable dynamic libraries). To know which image types are really
available, use image-type-available-p.
This function returns non-nil if images of type type can
be loaded and displayed. type must be an image type symbol.
For image types whose support libraries are statically linked, this
function always returns t. For image types whose support
libraries are dynamically loaded, it returns t if the library
could be loaded and nil otherwise.
An image descriptor is a list which specifies the underlying
data for an image, and how to display it. It is typically used as the
value of a display overlay or text property (see Other Display Specifications); but See Showing Images, for convenient helper
functions to insert images into buffers.
Each image descriptor has the form (image . props),
where props is a property list of alternating keyword symbols
and values, including at least the pair :type type that
specifies the image type.
Image descriptors which define image dimensions, :width,
:height, :max-width and :max-height, may take
either an integer, which represents the dimension in pixels, or a pair
(value . em), where value is the dimension’s
length in ems33. One em is equivalent to the size of the font
and value may be an integer or a float. Also, dimension can be
specified in (value . ch) and (value . cw)
forms, where ch means height of the canonical character and
cw means width of the canonical character.
The following is a list of properties that are meaningful for all image types (there are also properties which are meaningful only for certain image types, as documented in the following subsections):
:type typeThe image type. See Image Formats. Every image descriptor must include this property.
:file fileThis says to load the image from file file. If file is
not an absolute file name, it is expanded relative to each of the
directories mentioned by image-load-path (see Defining Images).
:data dataThis specifies the raw image data. Each image descriptor must have
either :data or :file, but not both.
For most image types, the value of a :data property should be a
string containing the image data. Some image types do not support
:data; for some others, :data alone is not enough, so
you need to use other image properties along with :data. See
the following subsections for details.
:margin marginThis specifies how many pixels to add as an extra margin around the
image. The value, margin, must be a non-negative number, or a
pair (x . y) of such numbers. If it is a pair,
x specifies how many pixels to add horizontally, and y
specifies how many pixels to add vertically. If :margin is not
specified, the default is zero.
:ascent ascentThis specifies the amount of the image’s height to use for its
ascent—that is, the part above the baseline. The value,
ascent, must be a number in the range 0 to 100, or the symbol
center.
If ascent is a number, that percentage of the image’s height is used for its ascent.
If ascent is center, the image is vertically centered
around a centerline which would be the vertical centerline of text drawn
at the position of the image, in the manner specified by the text
properties and overlays that apply to the image.
If this property is omitted, it defaults to 50.
:relief reliefThis adds a shadow rectangle around the image. The value, relief, specifies the width of the shadow lines, in pixels. If relief is negative, shadows are drawn so that the image appears as a pressed button; otherwise, it appears as an unpressed button.
:width width, :height heightThe :width and :height keywords are used for scaling the
image. If only one of them is specified, the other one will be
calculated so as to preserve the aspect ratio. If both are specified,
aspect ratio may not be preserved.
:max-width max-width, :max-height max-heightThe :max-width and :max-height keywords are used for
scaling if the size of the image exceeds these values. If
:width is set, it will have precedence over max-width,
and if :height is set, it will have precedence over
max-height, but you can otherwise mix these keywords as you
wish.
If both :max-width and :height are specified, but
:width is not, preserving the aspect ratio might require that
width exceeds :max-width. If this happens, scaling will use a
smaller value for the height so as to preserve the aspect ratio while
not exceeding :max-width. Similarly when both
:max-height and :width are specified, but :height
is not. For example, if you have a 200x100 image and specify that
:width should be 400 and :max-height should be 150,
you’ll end up with an image that is 300x150: Preserving the aspect
ratio and not exceeding the “max” setting. This combination of
parameters is a useful way of saying “display this image as large as
possible, but no larger than the available display area”.
:scale scaleThis should be a scaling factor for the image, a number. Values higher
than 1 mean to increase the image size, and lower values mean to
decrease the size, by multiplying both the width and height of the image
by the factor. For instance, a value of 0.25 will make the image a
quarter size of what it originally was. If the scaling makes the image
larger than specified by :max-width or :max-height, the
resulting size will not exceed those two values. If both :scale
and :height/:width are specified, the height/width will be
adjusted by the specified scaling factor.
The value of scale can also be the symbol default, which
means to use the value of image-scaling-factor. If that value is
a number, it is the scale factor to use; if it is auto (the
default), it means to compute the scaling factor based on pixel size of
the font used by the frame’s default face (see Low-Level Font Representation).
Specifically, if the pixel width of the default face’s font is greater
than 10, the image is enlarged by the factor computed as the ratio of
the font width to 10; if the font width is 10 pixels or less, the image
is not scaled. For example, if the default font’s width is 15, the
image will be scaled by the factor 1.5.
If scale is not provided, create-image scales the image
according to the value of image-scaling-factor.
:rotation angleSpecifies a rotation angle in degrees. Only multiples of 90 degrees
are supported, unless the image type is imagemagick. Positive
values rotate clockwise, negative values counter-clockwise. Rotation
is performed after scaling and cropping.
:flip flipIf this is t, the image will be horizontally flipped.
Currently it has no effect if the image type is imagemagick.
Vertical flipping can be achieved by rotating the image 180 degrees
and toggling this value.
:transform-smoothing smoothIf this is t, any image transform will have smoothing applied;
if nil, no smoothing will be applied. The exact algorithm used
is platform dependent, but should be equivalent to bilinear
filtering. Disabling smoothing will use the nearest neighbor
algorithm.
If this property is not specified, create-image will use the
image-transform-smoothing user option to say whether smoothing
should be done or not. This option can be nil (no smoothing),
t (use smoothing) or a predicate function that’s called with
the image object as the only parameter, and should return either
nil or t. The default is for down-scaling to apply
smoothing, and for large up-scaling to not apply smoothing.
:index frameSee Multi-Frame Images.
:conversion algorithmThis specifies a conversion algorithm that should be applied to the image before it is displayed; the value, algorithm, specifies which algorithm.
laplaceembossSpecifies the Laplace edge detection algorithm, which blurs out small differences in color while highlighting larger differences. People sometimes consider this useful for displaying the image for a disabled button.
(edge-detection :matrix matrix :color-adjust adjust) ¶Specifies a general edge-detection algorithm. matrix must be either a nine-element list or a nine-element vector of numbers. A pixel at position \(x/y\) in the transformed image is computed from original pixels around that position. matrix specifies, for each pixel in the neighborhood of \(x/y\), a factor with which that pixel will influence the transformed pixel; element \(0\) specifies the factor for the pixel at \(x-1/y-1\), element \(1\) the factor for the pixel at \(x/y-1\) etc., as shown below:
(x-1/y-1 x/y-1 x+1/y-1 x-1/y x/y x+1/y x-1/y+1 x/y+1 x+1/y+1)
The resulting pixel is computed from the color intensity of the color resulting from summing up the RGB values of surrounding pixels, multiplied by the specified factors, and dividing that sum by the sum of the factors’ absolute values.
Laplace edge-detection currently uses a matrix of
(1 0 0 0 0 0 0 0 -1)
Emboss edge-detection uses a matrix of
( 2 -1 0
-1 0 1
0 1 -2)
disabledSpecifies transforming the image so that it looks disabled.
:mask maskIf mask is heuristic or (heuristic bg), build
a clipping mask for the image, so that the background of a frame is
visible behind the image. If bg is not specified, or if bg
is t, determine the background color of the image by looking at
the four corners of the image, assuming the most frequently occurring
color from the corners is the background color of the image. Otherwise,
bg must be a list (red green blue)
specifying the color to assume for the background of the image.
If mask is nil, remove a mask from the image, if it has
one. Images in some formats include a mask which can be removed by
specifying :mask nil.
:pointer shapeThis specifies the pointer shape when the mouse pointer is over this image. See Pointer Shape, for available pointer shapes.
:map map ¶This associates an image map of hot spots with this image.
An image map is an alist where each element has the format
(area id plist). An area is specified
as either a rectangle, a circle, or a polygon.
A rectangle is a cons
(rect . ((x0 . y0) . (x1 . y1)))
which specifies the pixel coordinates of the upper left and bottom right
corners of the rectangle area.
A circle is a cons
(circle . ((x0 . y0) . r))
which specifies the center and the radius of the circle; r may
be a float or integer.
A polygon is a cons
(poly . [x0 y0 x1 y1 ...])
where each pair in the vector describes one corner in the polygon.
When the mouse pointer lies on a hot-spot area of an image, the
plist of that hot-spot is consulted; if it contains a help-echo
property, that defines a tool-tip for the hot-spot, and if it contains
a pointer property, that defines the shape of the mouse cursor when
it is on the hot-spot.
See Pointer Shape, for available pointer shapes.
When you click the mouse when the mouse pointer is over a hot-spot, an
event is composed by combining the id of the hot-spot with the
mouse event; for instance, [area4 mouse-1] if the hot-spot’s
id is area4.
Note that the map’s coordinates should reflect the displayed image
after all transforms have been done (rotation, scaling and so on), and
also note that Emacs (by default) performs auto-scaling of images, so
to make things match up, you should either specify :scale 1.0
when creating the image, or use the result of
image-compute-scaling-factor to compute the elements of the
map.
When an image’s :scale, :rotation, or :flip is
changed, :map will be recomputed based on the value of
:original-map and the values of those transformation.
:original-map original-map ¶This specifies the untransformed image map which will be used to
recompute :map after the image’s :scale, :rotation,
or :flip is changed.
If :original-map is not specified when creating an image with
create-image, it will be computed based on the supplied
:map, as well as any of :scale, :rotation, or
:flip which are non-nil.
Conversely, if :original-map is specified but :map is not,
:map will be computed based on :original-map,
:scale, :rotation, and :flip.
Set this user option to nil to prevent Emacs from automatically
recomputing an image :map based on its :original-map.
This function returns t if image spec has a mask bitmap.
frame is the frame on which the image will be displayed.
frame nil or omitted means to use the selected frame
(see Input Focus).
This function returns non-nil if frame supports image
scaling and rotation. frame nil or omitted means to use
the selected frame (see Input Focus). The returned list includes
symbols that indicate which image transform operations are supported:
scaleImage scaling is supported by frame via the :scale,
:width, :height, :max-width, and
:max-height properties.
rotate90Image rotation is supported by frame if the rotation angle is an integral multiple of 90 degrees.
If image transforms are not supported, :rotation, :crop,
:width, :height, :scale, :max-width and
:max-height will only be usable through ImageMagick, if
available (see ImageMagick Images).
To use XBM format, specify xbm as the image type. This image
format doesn’t require an external library, so images of this type are
always supported.
Additional image properties supported for the xbm image type are:
:foreground foregroundThe value, foreground, should be a string specifying the image
foreground color, or nil for the default color. This color is
used for each pixel in the XBM that is 1. The default is the frame’s
foreground color.
:background backgroundThe value, background, should be a string specifying the image
background color, or nil for the default color. This color is
used for each pixel in the XBM that is 0. The default is the frame’s
background color.
If you specify an XBM image using data within Emacs instead of an external file, use the following three properties:
:data dataThe value, data, specifies the contents of the image. There are three formats you can use for data:
:data-height and :data-width.
stride * height bits, where
stride is the smallest multiple of 8 greater than or equal to
the width of the image. In this case, you should specify
:data-height, :data-width and :stride, both to
indicate that the string contains just the bits rather than a whole
XBM file, and to specify the size of the image.
:stride strideThe number of bool vector entries stored for each row; the smallest multiple of 8 greater than or equal to width.
To use XPM format, specify xpm as the image type. The
additional image property :color-symbols is also meaningful with
the xpm image type:
:color-symbols symbolsThe value, symbols, should be an alist whose elements have the
form (name . color). In each element, name is
the name of a color as it appears in the image file, and color
specifies the actual color to use for displaying that name.
If your Emacs build has ImageMagick support, you can use the
ImageMagick library to load many image formats (see File
Conveniences in The GNU Emacs Manual). The image type symbol
for images loaded via ImageMagick is imagemagick, regardless of
the actual underlying image format.
To check for ImageMagick support, use the following:
(image-type-available-p 'imagemagick)
This function returns a list of image file extensions supported by the
current ImageMagick installation. Each list element is a symbol
representing an internal ImageMagick name for an image type, such as
BMP for .bmp images.
The value of this variable is a list of ImageMagick image types which
Emacs may attempt to render using ImageMagick. Each list element
should be one of the symbols in the list returned by
imagemagick-types, or an equivalent string. Alternatively, a
value of t enables ImageMagick for all possible image types.
Regardless of the value of this variable,
imagemagick-types-inhibit (see below) takes precedence.
The value of this variable lists the ImageMagick image types which
should never be rendered using ImageMagick, regardless of the value of
imagemagick-enabled-types. A value of t disables
ImageMagick entirely.
This variable is an alist mapping image types to file name extensions.
Emacs uses this in conjunction with the :format image property
(see below) to give a hint to the ImageMagick library as to the type
of an image. Each element has the form (type
extension), where type is a symbol specifying an image
content-type, and extension is a string that specifies the
associated file name extension.
Images loaded with ImageMagick support the following additional image descriptor properties:
:background backgroundbackground, if non-nil, should be a string specifying a
color, which is used as the image’s background color if the image
supports transparency. If the value is nil, it defaults to the
frame’s background color.
:format typeThe value, type, should be a symbol specifying the type of the
image data, as found in image-format-suffixes. This is used
when the image does not have an associated file name, to provide a
hint to ImageMagick to help it detect the image type.
:crop geometryThe value of geometry should be a list of the form
(width height x y). width and
height specify the width and height of the cropped image. If
x is a positive number it specifies the offset of the cropped
area from the left of the original image, and if negative the offset
from the right. If y is a positive number it specifies the
offset from the top of the original image, and if negative from the
bottom. If x or y are nil or unspecified the crop
area will be centered on the original image.
If the crop area is outside or overlaps the edge of the image it will
be reduced to exclude any areas outside of the image. This means it
is not possible to use :crop to increase the size of the image
by entering large width or height values.
Cropping is performed after scaling but before rotation.
SVG (Scalable Vector Graphics) is an XML format for specifying images. SVG images support the following additional image descriptor properties:
:foreground foregroundforeground, if non-nil, should be a string specifying a
color, which is used as the image’s foreground color. If the value is
nil, it defaults to the current face’s foreground color.
:background backgroundbackground, if non-nil, should be a string specifying a
color, which is used as the image’s background color if the image
supports transparency. If the value is nil, it defaults to the
current face’s background color.
:css csscss, if non-nil, should be a string specifying the CSS to
override the default CSS used when generating the image.
If your Emacs build has SVG support, you can create and manipulate these images with the following functions from the svg.el library.
Create a new, empty SVG image with the specified dimensions. args is an argument plist with you can specify following:
:stroke-widthThe default width (in pixels) of any lines created.
:strokeThe default stroke color on any lines created.
This function returns an SVG object, a Lisp data structure that specifies an SVG image, and all the following functions work on that structure. The argument svg in the following functions specifies such an SVG object.
Create a gradient in svg with identifier id. type
specifies the gradient type, and can be either linear or
radial. stops is a list of percentage/color pairs.
The following will create a linear gradient that goes from red at the start, to green 25% of the way, to blue at the end:
(svg-gradient svg "gradient1" 'linear
'((0 . "red") (25 . "green") (100 . "blue")))
The gradient created (and inserted into the SVG object) can later be used by all functions that create shapes.
All the following functions take an optional list of keyword parameters that alter the various attributes from their default values. Valid attributes include:
:stroke-widthThe width (in pixels) of lines drawn, and outlines around solid shapes.
:stroke-colorThe color of lines drawn, and outlines around solid shapes.
:fill-colorThe color used for solid shapes.
:idThe identified of the shape.
:gradientIf given, this should be the identifier of a previously defined gradient object.
:clip-pathIdentifier of a clip path.
Add to svg a rectangle whose upper left corner is at position x/y and whose size is width/height.
(svg-rectangle svg 100 100 500 500 :gradient "gradient1")
Add to svg a circle whose center is at x/y and whose radius is radius.
Add to svg an ellipse whose center is at x/y, and whose horizontal radius is x-radius and the vertical radius is y-radius.
Add to svg a line that starts at x1/y1 and extends to x2/y2.
Add to svg a multiple-segment line (a.k.a. “polyline”) that goes through points, which is a list of X/Y position pairs.
(svg-polyline svg '((200 . 100) (500 . 450) (80 . 100))
:stroke-color "green")
Add a polygon to svg where points is a list of X/Y pairs that describe the outer circumference of the polygon.
(svg-polygon svg '((100 . 100) (200 . 150) (150 . 90))
:stroke-color "blue" :fill-color "red")
Add the outline of a shape to svg according to commands, see SVG Path Commands.
Coordinates by default are absolute. To use coordinates relative to
the last position, or – initially – to the origin, set the attribute
:relative to t. This attribute can be specified for the
function or for individual commands. If specified for the function,
then all commands use relative coordinates by default. To make an
individual command use absolute coordinates, set :relative to
nil.
(svg-path svg '((moveto ((100 . 100))) (lineto ((200 . 0) (0 . 200) (-200 . 0))) (lineto ((100 . 100)) :relative nil)) :stroke-color "blue" :fill-color "lightblue" :relative t)
Add the specified text to svg.
(svg-text svg "This is a text" :font-size "40" :font-weight "bold" :stroke "black" :fill "white" :font-family "impact" :letter-spacing "4pt" :x 300 :y 400 :stroke-width 1)
Add an embedded (raster) image to svg. If datap is
nil, image should be a file name; otherwise it should be a
string containing the image data as raw bytes. image-type should be a
MIME image type, for instance "image/jpeg".
(svg-embed svg "~/rms.jpg" "image/jpeg" nil
:width "100px" :height "100px"
:x "50px" :y "75px")
To svg add an embedded (raster) image placed at
relative-filename. relative-filename is searched inside
file-name-directory of the :base-uri svg image property.
:base-uri specifies a (possibly non-existing) file name of the
svg image to be created, thus all the embedded files are searched
relatively to the :base-uri filename’s directory. If
:base-uri is omitted, then filename from where svg image is
loaded is used. Using :base-uri improves the performance of
embedding large images, comparing to svg-embed, because all the
work is done directly by librsvg.
;; Embedding /tmp/subdir/rms.jpg and /tmp/another/rms.jpg
(svg-embed-base-uri-image svg "subdir/rms.jpg"
:width "100px" :height "100px"
:x "50px" :y "75px")
(svg-embed-base-uri-image svg "another/rms.jpg"
:width "100px" :height "100px"
:x "75px" :y "50px")
(svg-image svg :scale 1.0
:base-uri "/tmp/dummy"
:width 175 :height 175)
Add a clipping path to svg. If applied to a shape via the :clip-path property, parts of that shape which lie outside of the clipping path are not drawn.
(let ((clip-path (svg-clip-path svg :id "foo")))
(svg-circle clip-path 200 200 175))
(svg-rectangle svg 50 50 300 300
:fill-color "red"
:clip-path "url(#foo)")
Add the custom node tag to svg.
(svg-node svg
'rect
:width 300 :height 200 :x 50 :y 100 :fill-color "green")
Remove the element with identifier id from the svg.
Finally, the svg-image takes an SVG object as its argument and
returns an image object suitable for use in functions like
insert-image.
Here’s a complete example that creates and inserts an image with a circle:
(let ((svg (svg-create 400 400 :stroke-width 10)))
(svg-gradient svg "gradient1" 'linear '((0 . "red") (100 . "blue")))
(svg-circle svg 200 200 100 :gradient "gradient1"
:stroke-color "green")
(insert-image (svg-image svg)))
SVG paths allow creation of complex images by combining lines, curves, arcs, and other basic shapes. The functions described below allow invoking SVG path commands from a Lisp program.
Move the pen to the first point in points. Additional points
are connected with lines. points is a list of X/Y coordinate
pairs. Subsequent moveto commands represent the start of a
new subpath.
(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100))))
:fill "white" :stroke "black")
End the current subpath by connecting it back to its initial point. A line is drawn along the connection.
(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100)))
(closepath)
(moveto ((75 . 125) (100 . 150) (125 . 125)))
(closepath))
:fill "red" :stroke "black")
Draw a line from the current point to the first element in points, a list of X/Y position pairs. If more than one point is specified, draw a polyline.
(svg-path svg '((moveto ((200 . 100)))
(lineto ((100 . 200) (0 . 100))))
:fill "yellow" :stroke "red")
Draw a horizontal line from the current point to the first element in x-coordinates. Specifying multiple coordinates is possible, although this usually doesn’t make sense.
(svg-path svg '((moveto ((100 . 200)))
(horizontal-lineto (300)))
:stroke "green")
Draw vertical lines.
(svg-path svg '((moveto ((200 . 100)))
(vertical-lineto (300)))
:stroke "green")
Using the first element in coordinate-sets, draw a cubic Bézier
curve from the current point. If there are multiple coordinate sets,
draw a polybezier. Each coordinate set is a list of the form
(x1 y1 x2 y2 x y), where
(x, y) is the curve’s end point. (x1, y1) and (x2, y2) are control points at the
beginning and at the end, respectively.
(svg-path svg '((moveto ((100 . 100)))
(curveto ((200 100 100 200 200 200)
(300 200 0 100 100 100))))
:fill "transparent" :stroke "red")
Using the first element in coordinate-sets, draw a cubic Bézier
curve from the current point. If there are multiple coordinate sets,
draw a polybezier. Each coordinate set is a list of the form
(x2 y2 x y), where (x, y) is the curve’s end point and (x2, y2) is the
corresponding control point. The first control point is the
reflection of the second control point of the previous command
relative to the current point, if that command was curveto
or smooth-curveto. Otherwise the first control point
coincides with the current point.
(svg-path svg '((moveto ((100 . 100)))
(curveto ((200 100 100 200 200 200)))
(smooth-curveto ((0 100 100 100))))
:fill "transparent" :stroke "blue")
Using the first element in coordinate-sets, draw a quadratic
Bézier curve from the current point. If there are multiple coordinate
sets, draw a polybezier. Each coordinate set is a list of the form
(x1 y1 x y), where (x, y) is the curve’s end point and (x1, y1) is the
control point.
(svg-path svg '((moveto ((200 . 100)))
(quadratic-bezier-curveto ((300 100 300 200)))
(quadratic-bezier-curveto ((300 300 200 300)))
(quadratic-bezier-curveto ((100 300 100 200)))
(quadratic-bezier-curveto ((100 100 200 100))))
:fill "transparent" :stroke "pink")
Using the first element in coordinate-sets, draw a quadratic
Bézier curve from the current point. If there are multiple coordinate
sets, draw a polybezier. Each coordinate set is a list of the form
(x y), where (x, y) is the curve’s
end point. The control point is the reflection of the control point
of the previous command relative to the current point, if that command
was quadratic-bezier-curveto or
smooth-quadratic-bezier-curveto. Otherwise the control
point coincides with the current point.
(svg-path svg '((moveto ((200 . 100)))
(quadratic-bezier-curveto ((300 100 300 200)))
(smooth-quadratic-bezier-curveto ((200 300)))
(smooth-quadratic-bezier-curveto ((100 200)))
(smooth-quadratic-bezier-curveto ((200 100))))
:fill "transparent" :stroke "lightblue")
Using the first element in coordinate-sets, draw an elliptical
arc from the current point. If there are multiple coordinate sets,
draw a sequence of elliptical arcs. Each coordinate set is a list of
the form (rx ry x y), where
(x, y) is the end point of the ellipse, and
(rx, ry) are its radii. Attributes may be appended to
the list:
:x-axis-rotationThe angle in degrees by which the x-axis of the ellipse is rotated relative to the x-axis of the current coordinate system.
:large-arcIf set to t, draw an arc sweep greater than or equal to 180
degrees. Otherwise, draw an arc sweep smaller than or equal to 180
degrees.
:sweepIf set to t, draw an arc in positive angle direction.
Otherwise, draw it in negative angle direction.
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350))))
:fill "transparent" :stroke "red")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :large-arc t))))
:fill "transparent" :stroke "green")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :sweep t))))
:fill "transparent" :stroke "blue")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :large-arc t
:sweep t))))
:fill "transparent" :stroke "gray")
(svg-path svg '((moveto ((160 . 100)))
(elliptical-arc ((40 100 80 0)))
(elliptical-arc ((40 100 -40 -70
:x-axis-rotation -120)))
(elliptical-arc ((40 100 -40 70
:x-axis-rotation -240))))
:stroke "pink" :fill "lightblue"
:relative t)
For PBM images, specify image type pbm. Color, gray-scale and
monochromatic images are supported. For mono PBM images, two additional
image properties are supported.
:foreground foregroundThe value, foreground, should be a string specifying the image
foreground color, or nil for the default color. This color is
used for each pixel in the PBM that is 1. The default is the frame’s
foreground color.
:background backgroundThe value, background, should be a string specifying the image
background color, or nil for the default color. This color is
used for each pixel in the PBM that is 0. The default is the frame’s
background color.
The remaining image types that Emacs can support are:
Image type gif.
Supports the :index property. See Multi-Frame Images.
Image type jpeg.
Image type png.
Image type tiff.
Supports the :index property. See Multi-Frame Images.
Image type webp.
The functions create-image, defimage and
find-image provide convenient ways to create image descriptors.
This function creates and returns an image descriptor which uses the
data in file-or-data. file-or-data can be a file name or
a string containing the image data; data-p should be nil
for the former case, non-nil for the latter case. If
file-or-data is a relative file name, the function will search
for it in directories mentioned in image-load-path.
The optional argument type is a symbol specifying the image type.
If type is omitted or nil, create-image tries to
determine the image type from the file’s first few bytes, or else
from the file’s name.
The remaining arguments, props, specify additional image properties—for example,
(create-image "foo.xpm" 'xpm nil :mask 'heuristic)
See Image Descriptors, for the list of supported properties. Some properties are specific to certain image types, and are described in subsections specific to those types.
The function returns nil if images of this type are not
supported. Otherwise it returns an image descriptor.
This macro defines symbol as an image name. The arguments specs is a list which specifies how to display the image. The third argument, doc, is an optional documentation string.
Each argument in specs has the form of a property list, and each
one should specify at least the :type property and either the
:file or the :data property. The value of :type
should be a symbol specifying the image type, the value of
:file is the file to load the image from, and the value of
:data is a string containing the actual image data. Here is an
example:
(defimage test-image ((:type xpm :file "~/test1.xpm") (:type xbm :file "~/test1.xbm")))
defimage tests each argument, one by one, to see if it is
usable—that is, if the type is supported and the file exists. The
first usable argument is used to make an image descriptor which is
stored in symbol.
If none of the alternatives will work, then symbol is defined
as nil.
Return the value of property in image. Properties can be
set by using setf. Setting a property to nil will
remove the property from the image.
This function provides a convenient way to find an image satisfying one of a list of image specifications specs.
Each specification in specs is a property list with contents
depending on image type. All specifications must at least contain the
properties :type type and either :file file
or :data data, where type is a symbol specifying
the image type, e.g., xbm, file is the file to load the
image from, and data is a string containing the actual image data.
The first specification in the list whose type is supported, and
file exists, is used to construct the image specification to be
returned. If no specification is satisfied, nil is returned.
The image is looked for in image-load-path.
This variable’s value is a list of locations in which to search for image files. If an element is a string or a variable symbol whose value is a string, the string is taken to be the name of a directory to search. If an element is a variable symbol whose value is a list, that is taken to be a list of directories to search.
The default is to search in the images subdirectory of the
directory specified by data-directory, then the directory
specified by data-directory, and finally in the directories in
load-path. Subdirectories are not automatically included in
the search, so if you put an image file in a subdirectory, you have to
supply the subdirectory explicitly. For example, to find the
image images/foo/bar.xpm within data-directory, you
should specify the image as follows:
(defimage foo-image '((:type xpm :file "foo/bar.xpm")))
This function returns a suitable search path for images used by the Lisp package library.
The function searches for image first using image-load-path,
excluding data-directory/images, and then in
load-path, followed by a path suitable for library, which
includes ../../etc/images and ../etc/images relative to
the library file itself, and finally in
data-directory/images.
Then this function returns a list of directories which contains first
the directory in which image was found, followed by the value of
load-path. If path is given, it is used instead of
load-path.
If no-error is non-nil and a suitable path can’t be
found, don’t signal an error. Instead, return a list of directories as
before, except that nil appears in place of the image directory.
Here is an example of using image-load-path-for-library:
(defvar image-load-path) ; shush compiler
(let* ((load-path (image-load-path-for-library
"mh-e" "mh-logo.xpm"))
(image-load-path (cons (car load-path)
image-load-path)))
(mh-tool-bar-folder-buttons-init))
Images are automatically scaled when created based on the
image-scaling-factor variable. The value is either a floating
point number (where numbers higher than 1 means to increase the size
and lower means to shrink the size), or the symbol auto, which
will compute a scaling factor based on the font pixel size. See Image Descriptors.
You can use an image descriptor by setting up the display
property yourself, but it is easier to use the functions in this
section.
This function inserts image in the current buffer at point. The
value image should be an image descriptor; it could be a value
returned by create-image, or the value of a symbol defined with
defimage. The argument string specifies the text to put
in the buffer to hold the image. If it is omitted or nil,
insert-image uses " " by default.
The argument area specifies whether to put the image in a margin.
If it is left-margin, the image appears in the left margin;
right-margin specifies the right margin. If area is
nil or omitted, the image is displayed at point within the
buffer’s text.
The argument slice specifies a slice of the image to insert. If
slice is nil or omitted the whole image is inserted.
(However, note that images are chopped on display at the window’s
right edge, because wrapping images is not supported.) Otherwise,
slice is a list (x y width
height) which specifies the x and y positions and
width and height of the image area to insert. Integer
values are in units of pixels. A floating-point number in the range
0.0–1.0 stands for that fraction of the width or height of the entire
image.
Internally, this function inserts string in the buffer, and gives
it a display property which specifies image. See The display Property. By default, doing interactive searches in the buffer will
consider string when searching. If inhibit-isearch is
non-nil, this is inhibited.
This function inserts image in the current buffer at point, like
insert-image, but splits the image into rowsxcols
equally sized slices.
Emacs displays each slice as a separate image, and allows more intuitive scrolling up/down, instead of jumping up/down the entire image when paging through a buffer that displays (large) images.
This function puts image image in front of pos in the current buffer. The argument pos should be an integer or a marker. It specifies the buffer position where the image should appear. The argument string specifies the text that should hold the image as an alternative to the default ‘x’.
The argument image must be an image descriptor, perhaps returned
by create-image or stored by defimage.
The argument area specifies whether to put the image in a margin.
If it is left-margin, the image appears in the left margin;
right-margin specifies the right margin. If area is
nil or omitted, the image is displayed at point within the
buffer’s text.
Internally, this function creates an overlay, and gives it a
before-string property containing text that has a display
property whose value is the image. (Whew! that was a mouthful…).
It returns the created overlay upon success, and also sets its
put-image property to t.
This function removes images in buffer between positions
start and end. If buffer is omitted or nil,
images are removed from the current buffer.
This removes only images that were put into buffer the way
put-image does it, not images that were inserted with
insert-image or in other ways.
This function returns the size of an image as a pair
(width . height). spec is an image
specification. pixels non-nil means return sizes measured
in pixels, otherwise return sizes measured in the default character size
of frame (see Frame Font). frame is the frame on which
the image will be displayed. frame nil or omitted means
use the selected frame (see Input Focus).
This variable is used to define the maximum size of image that Emacs will load. Emacs will refuse to load (and display) any image that is larger than this limit.
If the value is an integer, it directly specifies the maximum image height and width, measured in pixels. If it is floating point, it specifies the maximum image height and width as a ratio to the frame height and width. If the value is non-numeric, there is no explicit limit on the size of images.
The purpose of this variable is to prevent unreasonably large images
from accidentally being loaded into Emacs. It only takes effect the
first time an image is loaded. Once an image is placed in the image
cache, it can always be displayed, even if the value of
max-image-size is subsequently changed (see Image Cache).
This function returns t if point is on an image, and nil
otherwise.
Images inserted with the insertion functions above also get a local keymap installed in the text properties (or overlays) that span the displayed image. This keymap defines the following commands:
Increase the image size (image-increase-size)
Decrease the image size (image-decrease-size).
Rotate the image (image-rotate).
Flip the image horizontally (image-flip-horizontally).
Flip the image vertically (image-flip-vertically).
Save the image to a file (image-save).
Interactively crop the image (image-crop).
Interactively cut a rectangle from the image (image-cut).
See Image Mode in The GNU Emacs Manual, for more details about these image-specific key bindings.
Some image files can contain more than one image. We say that there are multiple “frames” in the image. At present, Emacs supports multiple frames for GIF, TIFF, and certain ImageMagick formats such as DJVM.
The frames can be used either to represent multiple pages (this is usually the case with multi-frame TIFF files, for example), or to create animation (usually the case with multi-frame GIF files).
A multi-frame image has a property :index, whose value is an
integer (counting from 0) that specifies which frame is being displayed.
This function returns non-nil if image contains more than
one frame. The actual return value is a cons (nimages
. delay), where nimages is the number of frames and
delay is the delay in seconds between them, or nil
if the image does not specify a delay. Images that are intended to be
animated usually specify a frame delay, whereas ones that are intended
to be treated as multiple pages do not.
This function returns the index of the current frame number for image, counting from 0.
This function switches image to frame number n. It
replaces a frame number outside the valid range with that of the end
of the range, unless nocheck is non-nil. If image
does not contain a frame with the specified number, the image displays
as a hollow box.
This function animates image. The optional integer index
specifies the frame from which to start (default 0). The optional
argument limit controls the length of the animation. If omitted
or nil, the image animates once only; if t it loops
forever; if a number animation stops after that many seconds.
Animation operates by means of a timer. Note that Emacs imposes a
minimum frame delay of 0.01 (image-minimum-frame-delay) seconds.
If the image itself does not specify a delay, Emacs uses
image-default-frame-delay.
This function returns the timer responsible for animating image, if there is one.
Emacs caches images so that it can display them again more
efficiently. When Emacs displays an image, it searches the image
cache for an existing image specification equal to the desired
specification. If a match is found, the image is displayed from the
cache. Otherwise, Emacs loads the image normally.
This function removes the image with specification spec from the
image cache of frame frame. Image specifications are compared
using equal. If frame is nil, it defaults to the
selected frame. If frame is t, the image is flushed on
all existing frames.
In Emacs’s current implementation, each graphical terminal possesses an image cache, which is shared by all the frames on that terminal (see Multiple Terminals). Thus, refreshing an image in one frame also refreshes it in all other frames on the same terminal.
One use for image-flush is to tell Emacs about a change in an
image file. If an image specification contains a :file
property, the image is cached based on the file’s contents when the
image is first displayed. Even if the file subsequently changes,
Emacs continues displaying the old version of the image. Calling
image-flush flushes the image from the cache, forcing Emacs to
re-read the file the next time it needs to display that image.
Another use for image-flush is for memory conservation. If
your Lisp program creates a large number of temporary images over a
period much shorter than image-cache-eviction-delay (see
below), you can opt to flush unused images yourself, instead of
waiting for Emacs to do it automatically.
This function clears an image cache, removing all the images stored in
it. If filter is omitted or nil, it clears the cache for
the selected frame. If filter is a frame, it clears the cache
for that frame. If filter is t, all image caches are
cleared. Otherwise, filter is taken to be a file name, and all
images associated with that file name are removed from all image
caches.
If an image in the image cache has not been displayed for a specified period of time, Emacs removes it from the cache and frees the associated memory.
This variable specifies the number of seconds an image can remain in the cache without being displayed. When an image is not displayed for this length of time, Emacs removes it from the image cache.
Under some circumstances, if the number of images in the cache grows too large, the actual eviction delay may be shorter than this.
If the value is nil, Emacs does not remove images from the cache
except when you explicitly clear it. This mode can be useful for
debugging.
This function returns the total size of the current image cache, in bytes. An image of size 200x100 with 24 bits per color will have a cache size of 60000 bytes, for instance.
Emacs sometimes uses buttons (for clicking on) or small graphics (to illustrate something). Since Emacs is available on a wide variety of systems with different capabilities, and users have different preferences, Emacs provides a facility to handle this in a convenient way, allowing customization, graceful degradation, accessibility, as well as themability: Icons.
The central macro here is define-icon, and here’s a simple
example:
(define-icon outline-open button
'((image "right.svg" "open.xpm" "open.pbm" :height line)
(emoji "▶️")
(symbol "▶" "➤")
(text "open" :face icon-button))
"Icon used for buttons for opening a section in outline buffers."
:version "29.1"
:help-echo "Open this section")
Which alternative will actually be displayed depends on the value of
the user option icon-preference (see Icons in The GNU
Emacs Manual) and on the results of run-time checks for what the
current frame’s terminal can actually display.
The macro in the example above defines outline-open as an icon,
and inherits properties from the icon called button (so this is
meant as a clickable button to be inserted in a buffer). It is
followed by a list of icon types along with the actual icon
shapes themselves. In addition, there’s a doc string and various
keywords that contain additional information and properties.
To instantiate an icon, you use icon-string, which will
consult the current Customize theming, and the icon-preference
user option, and finally what the Emacs is able to actually display.
If icon-preference is (image emoji symbol text) (i.e.,
allowing all of these forms of icons), in this case,
icon-string will first check that Emacs is able to display
images at all, and then whether it has support for each of those
different image formats. If that fails, Emacs will check whether
Emacs can display emojis (in the current frame). If that fails, it’ll
check whether it can display the symbol in question. If that fails,
it’ll use the plain text version.
For instance, if icon-preference doesn’t contain image
or emoji, it’ll skip those entries.
Code can confidently call icon-string in all circumstances and
be sure that something readable will appear on the screen, no
matter whether the user is on a graphical terminal or a text terminal,
and no matter which features Emacs was built with.
Define an icon name, a symbol, with the display alternatives in
spec, that can be later instantiated using icon-string.
The name is the name of the resulting keyword.
The resulting icon will inherit specs from parent, and from their parent’s parents, and so on, and the lowest descendent element wins.
specs is a list of icon specifications. The first element of each specification is the type, and the rest is something that can be used as an icon of that type, and then optionally followed by a keyword list. The following icon types are available:
imageIn this case, there may be many images listed as candidates. Emacs
will choose the first one that the current Emacs instance can show.
If an image is listed is an absolute file name, it’s used as is, but it’s
otherwise looked up in the list image-load-path
(see Defining Images).
emojiThis should be a (possibly colorful) emoji.
symbolThis should be a (monochrome) symbol character.
textIcons should also have a textual fallback. This can also be used for
the visually impaired: if icon-preference is just
(text), all icons will be replaced by text.
Various keywords may follow the list of icon specifications. For instance:
(symbol "▶" "➤" :face icon-button)
Unknown keywords are ignored. The following keywords are allowed:
:faceThe face to be used for the icon.
:heightThis is only valid for image icons, and can be either a number
(which specifies the height in pixels), or the symbol line,
which will use the default line height in the currently selected
window.
:widthThis is only valid for image icons, and can be either a number
(which specifies the width in pixels), or the symbol font,
which will use the width in pixels of the current buffer’s default
face font.
doc should be a doc string.
keywords is a list of keyword/value pairs. The following keywords are allowed:
:versionThe (approximate) Emacs version this button first appeared. (This keyword is mandatory.)
:groupThe customization group this icon belongs in. If not present, it is inferred.
:help-echoThe help string shown when hovering over the icon with the mouse pointer.
This function returns a string suitable for display in the current buffer for icon.
Alternatively, you can get a “deconstructed” version of icon
with this function. It returns a plist (see 属性列表) where
the keys are string, face and image. (The latter
is only present if the icon is represented by an image.) This can be
useful if the icon isn’t to be inserted directly in the buffer, but
needs some sort of pre-processing first.
Icons can be customized with M-x customize-icon. Themes can specify changes to icons with, for instance:
(custom-theme-set-icons
'my-theme
'(outline-open ((image :height 100)
(text " OPEN ")))
'(outline-close ((image :height 100)
(text " CLOSE " :face warning))))
Emacs is able to display native widgets, such as GTK+ WebKit widgets,
in Emacs buffers when it was built with the necessary support
libraries and is running on a graphical terminal. To test whether
Emacs supports display of embedded widgets, check that the
xwidget-internal feature is available (see 功能).
To display an embedded widget in a buffer, you must first create an
xwidget object, and then use that object as the display specifier
in a display text or overlay property (see The display Property).
Embedded widgets can send events notifying Lisp code about changes occurring within them. (see Xwidget 事件).
This creates and returns an xwidget object. If
buffer is omitted or nil, it defaults to the current
buffer. If buffer names a buffer that doesn’t exist, it will be
created. The type identifies the type of the xwidget component,
it can be one of the following:
webkitThe WebKit component.
The width and height arguments specify the widget size in pixels, and title, a string, specifies its title. related is used internally by the WebKit widget, and specifies another WebKit widget that the newly created widget should share settings and subprocesses with.
The xwidget that is returned will be killed alongside its buffer
(see Killing Buffers). You can also kill it using
kill-xwidget. Once it is killed, the xwidget may continue to
exist as a Lisp object and act as a display property until all
references to it are gone, but most actions that can be performed on
live xwidgets will no longer be available.
This function returns t if object is an xwidget,
nil otherwise.
This function returns t if object is an xwidget that
hasn’t been killed, and nil otherwise.
This function kills xwidget, by removing it from its buffer and releasing window system resources it holds.
This function returns the property list of xwidget.
This function replaces the property list of xwidget with a new property list given by plist.
This function returns the buffer of xwidget. If xwidget
has been killed, it returns nil.
This function sets the buffer of xwidget to buffer.
This function returns a list of xwidget objects associated with the
buffer, which can be specified as a buffer object or a name of
an existing buffer, a string. The value is nil if buffer
contains no xwidgets.
This function browses the specified uri in the given xwidget. The uri is a string that specifies the name of a file or a URL.
This function causes the browser widget specified by xwidget to
execute the specified JavaScript script.
This function returns the title of xwidget as a string.
This function resizes the specified xwidget to the size widthxheight pixels.
This function returns the desired size of xwidget as a list of
the form (width height). The dimensions are in
pixels.
This function returns the attributes of xwidget as a vector of
the form [type title width height].
The attributes are usually determined by make-xwidget when the
xwidget is created.
This function allows you to arrange that Emacs will ask the user for
confirmation before exiting or before killing a buffer that has
xwidget associated with it. If flag is non-nil,
Emacs will query the user, otherwise it will not.
This function returns the current setting of xwidgets
query-on-exit flag, either t or nil.
Send an input event event to xwidget. The precise action performed is platform-specific. See 输入事件.
You can optionally pass the frame on which the event was generated via
frame. On X11, modifier keys in key events will not be
considered if frame is nil, and the selected frame is not
an X-Windows frame.
On GTK, only keyboard and function key events are supported. Mouse, motion, and click events are dispatched to the xwidget without going through Lisp code, and as such shouldn’t require this function to be called.
Start an incremental search on the WebKit widget xwidget with the string query as the query. case-insensitive denotes whether or not the search is case-insensitive, backwards determines if the search is performed backwards towards the start of the document, and wrap-around determines whether or not the search terminates at the end of the document.
If the function is called while a search query is already present, then the query specified here will replace the existing query.
To stop a search query, use xwidget-webkit-finish-search.
Display the next search result in xwidget. This function will
signal an error if a search query has not been already started in
xwidget through xwidget-webkit-search.
If wrap-around was non-nil when xwidget-webkit-search
was called, then the search will restart from the beginning of the
document when its end is reached.
Display the previous search result in xwidget. This function
signals an error if a search query has not been already started in
xwidget through xwidget-webkit-search.
If wrap-around was non-nil when xwidget-webkit-search
was called, then the search will restart from the end of the
document when its beginning is reached.
Finish a search operation started with xwidget-webkit-search in
xwidget. If there is no query currently ongoing, this function
signals an error.
Load text, a string, into xwidget, which should be a WebKit xwidget. Any HTML markup in text will be processed by xwidget while rendering the text.
Optional argument base-uri, which should be a string, specifies the absolute location of the web resources referenced by text, to be used for resolving relative links in text.
Make xwidget, a WebKit widget, load the rel-posth element in its navigation history.
If rel-pos is zero, the current page will be reloaded instead.
Return the navigation history of xwidget, up to limit items in each direction. If not specified, limit defaults to 50.
The returned value is a list of the form (back here forward), where here is the current
navigation item, while back is a list of items containing the
items recorded by WebKit before the current navigation item, and
forward is a list of items recorded after the current navigation
item. back, here and forward can all be nil.
When here is nil, it means that no items have been
recorded yet; if back or forward are nil, it means
that there is no history recorded before or after the current item
respectively.
Navigation items are themselves lists of the form (idx title uri). In these lists, idx is an index that
can be passed to xwidget-webkit-goto-history, title is
the human-readable title of the item, and uri is the URI of the
item. The user should normally have no reason to load uri
manually to reach a specific history item. Instead, idx should
be passed as an index to xwidget-webkit-goto-history.
Return an estimate of how much data is remaining to be transferred before the page displayed by the WebKit widget xwidget is fully loaded.
The value returned is a float ranging between 0.0 and 1.0.
Make the WebKit widget xwidget store cookies in file.
file must be an absolute file name. The new setting will also
affect any xwidget that was created with xwidget as the
related argument to make-xwidget, and widgets related to
those as well.
If this function is not called at least once on xwidget or a related widget, xwidget will not store cookies on disk at all.
Terminate any data transfer still in progress in the WebKit widget xwidget as part of a page-loading operation. If a page is not being loaded, this function does nothing.
The Button package defines functions for inserting and manipulating buttons that can be activated with the mouse or via keyboard commands. These buttons are typically used for various kinds of hyperlinks.
A button is essentially a set of text or overlay properties, attached to a stretch of text in a buffer. These properties are called button properties. One of these properties, the action property, specifies a function which is called when the user invokes the button using the keyboard or the mouse. The action function may examine the button and use its other properties as desired.
In some ways, the Button package duplicates the functionality in the Widget package. See Introduction in The Emacs Widget Library. The advantage of the Button package is that it is faster, smaller, and simpler to program. From the point of view of the user, the interfaces produced by the two packages are very similar.
Each button has an associated list of properties defining its appearance and behavior, and other arbitrary properties may be used for application specific purposes. The following properties have special meaning to the Button package:
action ¶The function to call when the user invokes the button, which is passed
the single argument button. By default this is ignore,
which does nothing.
mouse-action ¶This is similar to action, and when present, will be used
instead of action for button invocations resulting from
mouse-clicks (instead of the user hitting RET). If not
present, mouse-clicks use action instead.
face ¶This is an Emacs face controlling how buttons of this type are
displayed; by default this is the button face.
mouse-face ¶This is an additional face which controls appearance during
mouse-overs (merged with the usual button face); by default this is
the usual Emacs highlight face.
keymap ¶The button’s keymap, defining bindings active within the button
region. By default this is the usual button region keymap, stored
in the variable button-map, which defines RET and
mouse-2 to invoke the button.
type ¶The button type. See Button Types.
help-echo ¶A string displayed by the Emacs tooltip help system; by default,
"mouse-2, RET: Push this button". Alternatively, a function
that returns, or a form that evaluates to, a string to be displayed or
nil. For details see Text help-echo.
The function is called with three arguments, window,
object, and pos. The second argument, object, is
either the overlay that had the property (for overlay buttons), or the
buffer containing the button (for text property buttons). The other
arguments have the same meaning as for the special text property
help-echo.
follow-link ¶The follow-link property, defining how a mouse-1 click
behaves on this button, See Defining Clickable Text.
button ¶All buttons have a non-nil button property, which may be useful
in finding regions of text that comprise buttons (which is what the
standard button functions do).
There are other properties defined for the regions of text in a button, but these are not generally interesting for typical uses.
Every button has a button type, which defines default values for the button’s properties. Button types are arranged in a hierarchy, with specialized types inheriting from more general types, so that it’s easy to define special-purpose types of buttons for specific tasks.
Define a button type called name (a symbol).
The remaining arguments
form a sequence of property value pairs, specifying default
property values for buttons with this type (a button’s type may be set
by giving it a type property when creating the button, using
the :type keyword argument).
In addition, the keyword argument :supertype may be used to
specify a button-type from which name inherits its default
property values. Note that this inheritance happens only when
name is defined; subsequent changes to a supertype are not
reflected in its subtypes.
Using define-button-type to define default properties for
buttons is not necessary—buttons without any specified type use the
built-in button-type button—but it is encouraged, since
doing so usually makes the resulting code clearer and more efficient.
Buttons are associated with a region of text, using an overlay or
text properties to hold button-specific information, all of which are
initialized from the button’s type (which defaults to the built-in
button type button). Like all Emacs text, the appearance of
the button is governed by the face property; by default (via
the face property inherited from the button button-type)
this is a simple underline, like a typical web-page link.
For convenience, there are two sorts of button-creation functions,
those that add button properties to an existing region of a buffer,
called make-...button, and those that also insert the button
text, called insert-...button.
The button-creation functions all take the &rest argument
properties, which should be a sequence of property value
pairs, specifying properties to add to the button; see Button Properties. In addition, the keyword argument :type may be
used to specify a button-type from which to inherit other properties;
see Button Types. Any properties not explicitly specified
during creation will be inherited from the button’s type (if the type
defines such a property).
The following functions add a button using an overlay (see Overlays) to hold the button properties:
This makes a button from beg to end in the current buffer, and returns it.
This inserts a button with the label label at point, and returns it.
The following functions are similar, but using text properties (see Text Properties) to hold the button properties. Such buttons do not add markers to the buffer, so editing in the buffer does not slow down if there is an extremely large numbers of buttons. However, if there is an existing face text property on the text (e.g., a face assigned by Font Lock mode), the button face may not be visible. Both of these functions return the starting position of the new button.
This makes a button from beg to end in the current buffer, using text properties.
This inserts a button with the label label at point, using text properties.
Sometimes it’s more convenient to make a string into a button without
inserting it into a buffer immediately, for instance when creating
data structures that may then, later, be inserted into a buffer. This
function makes string into such a string, and callback
will be called when the user clicks on the button. The optional
data parameter will be used as the parameter when callback
is called. If nil, the button is used as the parameter instead.
Sometimes it’s more convenient to convert existing text in a buffer to a
button instead of inserting new text. This function makes the region
between start and end into a button. Arguments
callback and data have the same meanings as for
buttonize. Optional argument help-echo is used as the
help-echo property of the button.
These are functions for getting and setting properties of buttons. Often these are used by a button’s invocation function to determine what to do.
Where a button parameter is specified, it means an object referring to a specific button, either an overlay (for overlay buttons), or a buffer-position or marker (for text property buttons). Such an object is passed as the first argument to a button’s invocation function when it is invoked.
Return the position at which button starts.
Return the position at which button ends.
Get the property of button button named prop.
Set button’s prop property to val.
Call button’s action property (i.e., invoke the function
that is the value of that property, passing it the single argument
button). If use-mouse-action is non-nil, try to
invoke the button’s mouse-action property instead of
action; if the button has no mouse-action property, use
action as normal. If the button-data property is
present in button, use that as the argument for the
action function instead of button.
Return button’s text label.
Return button’s button-type.
Return t if button has button-type type, or one of
type’s subtypes.
Return the button at position pos in the current buffer, or
nil. If the button at pos is a text property button, the
return value is a marker pointing to pos.
Set the button-type type’s prop property to val.
Get the property of button-type type named prop.
Return t if button-type type is a subtype of supertype.
These are commands and functions for locating and operating on buttons in an Emacs buffer.
push-button is the command that a user uses to actually push
a button, and is bound by default in the button itself to RET
and to mouse-2 using a local keymap in the button’s overlay or
text properties. Commands that are useful outside the buttons itself,
such as forward-button and backward-button are
additionally available in the keymap stored in
button-buffer-map; a mode which uses buttons may want to use
button-buffer-map as a parent keymap for its keymap.
Alternatively, the button-mode can be switched on for much the
same effect: It’s a minor mode that does nothing else than install
button-buffer-map as a minor mode keymap.
If the button has a non-nil follow-link property, and
mouse-1-click-follows-link is set, a quick mouse-1 click
will also activate the push-button command.
See Defining Clickable Text.
Perform the action specified by a button at location pos.
pos may be either a buffer position or a mouse-event. If
use-mouse-action is non-nil, or pos is a
mouse-event (see 鼠标事件), try to invoke the button’s
mouse-action property instead of action; if the button
has no mouse-action property, use action as normal.
pos defaults to point, except when push-button is invoked
interactively as the result of a mouse-event, in which case, the mouse
event’s position is used. If there’s no button at pos, do
nothing and return nil, otherwise return t.
Move to the nth next button, or nth previous button if
n is negative. If n is zero, move to the start of any
button at point. If wrap is non-nil, moving past either
end of the buffer continues from the other end. If
display-message is non-nil, the button’s help-echo string
is displayed. Any button with a non-nil skip property
is skipped over. Returns the button found, and signals an error if no
buttons can be found. If no-error is non-nil, return nil
instead of signaling the error.
Move to the nth previous button, or nth next button if
n is negative. If n is zero, move to the start of any
button at point. If wrap is non-nil, moving past either
end of the buffer continues from the other end. If
display-message is non-nil, the button’s help-echo string
is displayed. Any button with a non-nil skip property
is skipped over. Returns the button found, and signals an error if no
buttons can be found. If no-error is non-nil, return nil
instead of signaling the error.
Return the next button after (for next-button) or before (for
previous-button) position pos in the current buffer. If
count-current is non-nil, count any button at pos
in the search, instead of starting at the next button.
The Ewoc package constructs buffer text that represents a structure of Lisp objects, and updates the text to follow changes in that structure. This is like the “view” component in the “model–view–controller” design paradigm. Ewoc means “Emacs’s Widget for Object Collections”.
An ewoc is a structure that organizes information required to construct buffer text that represents certain Lisp data. The buffer text of the ewoc has three parts, in order: first, fixed header text; next, textual descriptions of a series of data elements (Lisp objects that you specify); and last, fixed footer text. Specifically, an ewoc contains information on:
Typically, you define an ewoc with ewoc-create, and then pass
the resulting ewoc structure to other functions in the Ewoc package to
build nodes within it, and display it in the buffer. Once it is
displayed in the buffer, other functions determine the correspondence
between buffer positions and nodes, move point from one node’s textual
representation to another, and so forth. See Abstract Display Functions.
A node encapsulates a data element much the way a variable holds a value. Normally, encapsulation occurs as a part of adding a node to the ewoc. You can retrieve the data element value and place a new value in its place, like so:
(ewoc-data node) ⇒ value (ewoc-set-data node new-value) ⇒ new-value
You can also use, as the data element value, a Lisp object (list or vector) that is a container for the real value, or an index into some other structure. The example (see Abstract Display Example) uses the latter approach.
When the data changes, you will want to update the text in the
buffer. You can update all nodes by calling ewoc-refresh, or
just specific nodes using ewoc-invalidate, or all nodes
satisfying a predicate using ewoc-map. Alternatively, you can
delete invalid nodes using ewoc-delete or ewoc-filter,
and add new nodes in their place. Deleting a node from an ewoc deletes
its associated textual description from buffer, as well.
In this subsection, ewoc and node stand for the structures described above (see Abstract Display), while data stands for an arbitrary Lisp object used as a data element.
This constructs and returns a new ewoc, with no nodes (and thus no data
elements). pretty-printer should be a function that takes one
argument, a data element of the sort you plan to use in this ewoc, and
inserts its textual description at point using insert (and never
insert-before-markers, because that would interfere with the
Ewoc package’s internal mechanisms).
Normally, a newline is automatically inserted after the header,
the footer and every node’s textual description. If nosep
is non-nil, no newline is inserted. This may be useful for
displaying an entire ewoc on a single line, for example, or for
making nodes invisible by arranging for pretty-printer
to do nothing for those nodes.
An ewoc maintains its text in the buffer that is current when
you create it, so switch to the intended buffer before calling
ewoc-create.
This returns the buffer where ewoc maintains its text.
This returns a cons cell (header . footer)
made from ewoc’s header and footer.
This sets the header and footer of ewoc to the strings header and footer, respectively.
These add a new node encapsulating data, putting it, respectively, at the beginning or end of ewoc’s chain of nodes.
These add a new node encapsulating data, adding it to ewoc before or after node, respectively.
These return, respectively, the previous node and the next node of node in ewoc.
This returns the node in ewoc found at zero-based index n.
A negative n means count from the end. ewoc-nth returns
nil if n is out of range.
This extracts the data encapsulated by node and returns it.
This sets the data encapsulated by node to data.
This determines the node in ewoc which contains point (or
pos if specified), and returns that node. If ewoc has no
nodes, it returns nil. If pos is before the first node,
it returns the first node; if pos is after the last node, it returns
the last node. The optional third arg guess
should be a node that is likely to be near pos; this doesn’t
alter the result, but makes the function run faster.
This returns the start position of node.
These move point to the previous or next, respectively, argth node
in ewoc. ewoc-goto-prev does not move if it is already at
the first node or if ewoc is empty, whereas ewoc-goto-next
moves past the last node, returning nil. Excepting this special
case, these functions return the node moved to.
This moves point to the start of node in ewoc.
This function regenerates the text of ewoc. It works by deleting the text between the header and the footer, i.e., all the data elements’ representations, and then calling the pretty-printer function for each node, one by one, in order.
This is similar to ewoc-refresh, except that only nodes in
ewoc are updated instead of the entire set.
This deletes each node in nodes from ewoc.
This calls predicate for each data element in ewoc and
deletes those nodes for which predicate returns nil.
Any args are passed to predicate.
This calls predicate for each data element in ewoc
and returns a list of those elements for which predicate
returns non-nil. The elements in the list are ordered
as in the buffer. Any args are passed to predicate.
This calls map-function for each data element in ewoc and
updates those nodes for which map-function returns non-nil.
Any args are passed to map-function.
Here is a simple example using functions of the ewoc package to implement a color components display, an area in a buffer that represents a vector of three integers (itself representing a 24-bit RGB value) in various ways.
(setq colorcomp-ewoc nil
colorcomp-data nil
colorcomp-mode-map nil
colorcomp-labels ["Red" "Green" "Blue"])
(defun colorcomp-pp (data)
(if data
(let ((comp (aref colorcomp-data data)))
(insert (aref colorcomp-labels data) "\t: #x"
(format "%02X" comp) " "
(make-string (ash comp -2) ?#) "\n"))
(let ((cstr (format "#%02X%02X%02X"
(aref colorcomp-data 0)
(aref colorcomp-data 1)
(aref colorcomp-data 2)))
(samp " (sample text) "))
(insert "Color\t: "
(propertize samp 'face
`(foreground-color . ,cstr))
(propertize samp 'face
`(background-color . ,cstr))
"\n"))))
(defun colorcomp (color)
"Allow fiddling with COLOR in a new buffer.
The buffer is in Color Components mode."
(interactive "sColor (name or #RGB or #RRGGBB): ")
(when (string= "" color)
(setq color "green"))
(unless (color-values color)
(error "No such color: %S" color))
(switch-to-buffer
(generate-new-buffer (format "originally: %s" color)))
(kill-all-local-variables)
(setq major-mode 'colorcomp-mode
mode-name "Color Components")
(use-local-map colorcomp-mode-map)
(erase-buffer)
(buffer-disable-undo)
(let ((data (apply 'vector (mapcar (lambda (n) (ash n -8))
(color-values color))))
(ewoc (ewoc-create 'colorcomp-pp
"\nColor Components\n\n"
(substitute-command-keys
"\n\\{colorcomp-mode-map}"))))
(set (make-local-variable 'colorcomp-data) data)
(set (make-local-variable 'colorcomp-ewoc) ewoc)
(ewoc-enter-last ewoc 0)
(ewoc-enter-last ewoc 1)
(ewoc-enter-last ewoc 2)
(ewoc-enter-last ewoc nil)))
This example can be extended to be a color selection widget (in
other words, the “controller” part of the “model–view–controller”
design paradigm) by defining commands to modify colorcomp-data
and to finish the selection process, and a keymap to tie it all
together conveniently.
(defun colorcomp-mod (index limit delta)
(let ((cur (aref colorcomp-data index)))
(unless (= limit cur)
(aset colorcomp-data index (+ cur delta)))
(ewoc-invalidate
colorcomp-ewoc
(ewoc-nth colorcomp-ewoc index)
(ewoc-nth colorcomp-ewoc -1))))
(defun colorcomp-R-more () (interactive) (colorcomp-mod 0 255 1))
(defun colorcomp-G-more () (interactive) (colorcomp-mod 1 255 1))
(defun colorcomp-B-more () (interactive) (colorcomp-mod 2 255 1))
(defun colorcomp-R-less () (interactive) (colorcomp-mod 0 0 -1))
(defun colorcomp-G-less () (interactive) (colorcomp-mod 1 0 -1))
(defun colorcomp-B-less () (interactive) (colorcomp-mod 2 0 -1))
(defun colorcomp-copy-as-kill-and-exit ()
"Copy the color components into the kill ring and kill the buffer.
The string is formatted #RRGGBB (hash followed by six hex digits)."
(interactive)
(kill-new (format "#%02X%02X%02X"
(aref colorcomp-data 0)
(aref colorcomp-data 1)
(aref colorcomp-data 2)))
(kill-buffer nil))
(setq colorcomp-mode-map
(define-keymap :suppress t
"i" 'colorcomp-R-less
"o" 'colorcomp-R-more
"k" 'colorcomp-G-less
"l" 'colorcomp-G-more
"," 'colorcomp-B-less
"." 'colorcomp-B-more
"SPC" 'colorcomp-copy-as-kill-and-exit))
Note that we never modify the data in each node, which is fixed when the
ewoc is created to be either nil or an index into the vector
colorcomp-data, the actual color components.
This section describes the mechanism by which Emacs shows a matching open parenthesis when the user inserts a close parenthesis.
The value of this variable should be a function (of no arguments) to
be called whenever a character with close parenthesis syntax is inserted.
The value of blink-paren-function may be nil, in which
case nothing is done.
If this variable is nil, then blink-matching-open does
nothing.
This variable specifies the maximum distance to scan for a matching parenthesis before giving up.
This variable specifies the number of seconds to keep indicating the matching parenthesis. A fraction of a second often gives good results, but the default is 1, which works on all systems.
This function is the default value of blink-paren-function. It
assumes that point follows a character with close parenthesis syntax
and applies the appropriate effect momentarily to the matching opening
character. If that character is not already on the screen, it
displays the character’s context in the echo area. To avoid long
delays, this function does not search farther than
blink-matching-paren-distance characters.
Here is an example of calling this function explicitly.
(defun interactive-blink-matching-open () "Indicate momentarily the start of parenthesized sexp before point." (interactive)
(let ((blink-matching-paren-distance
(buffer-size))
(blink-matching-paren t))
(blink-matching-open)))
This section describes how characters are actually displayed by Emacs. Typically, a character is displayed as a glyph (a graphical symbol which occupies one character position on the screen), whose appearance corresponds to the character itself. For example, the character ‘a’ (character code 97) is displayed as ‘a’. Some characters, however, are displayed specially. For example, the formfeed character (character code 12) is usually displayed as a sequence of two glyphs, ‘^L’, while the newline character (character code 10) starts a new screen line.
You can modify how each character is displayed by defining a display table, which maps each character code into a sequence of glyphs. See Display Tables.
Here are the conventions for displaying each character code (in the absence of a display table, which can override these conventions; see Display Tables).
tab-width controls the number of
spaces per tab stop (see below).
ctl-arrow. If this variable is non-nil (the default),
these characters are displayed as sequences of two glyphs, where the
first glyph is ‘^’ (a display table can specify a glyph to use
instead of ‘^’); e.g., the DEL character is displayed as
‘^?’.
If ctl-arrow is nil, these characters are displayed as
octal escapes (see below).
This rule also applies to carriage return (character code 13), if that character appears in the buffer. But carriage returns usually do not appear in buffer text; they are eliminated as part of end-of-line conversion (see Basic Concepts of Coding Systems).
The above display conventions apply even when there is a display
table, for any character whose entry in the active display table is
nil. Thus, when you set up a display table, you need only
specify the characters for which you want special display behavior.
The following variables affect how certain characters are displayed
on the screen. Since they change the number of columns the characters
occupy, they also affect the indentation functions. They also affect
how the mode line is displayed; if you want to force redisplay of the
mode line using the new values, call the function
force-mode-line-update (see 模式行格式).
This buffer-local variable controls how control characters are
displayed. If it is non-nil, they are displayed as a caret
followed by the character: ‘^A’. If it is nil, they are
displayed as octal escapes: a backslash followed by three octal
digits, as in ‘\001’.
The value of this buffer-local variable is the spacing between tab
stops used for displaying tab characters in Emacs buffers. The value
is in units of columns, and the default is 8. Note that this feature
is completely independent of the user-settable tab stops used by the
command tab-to-tab-stop. See Adjustable Tab Stops.
A display table is a special-purpose char-table
(see 字符表), with display-table as its subtype, which
is used to override the usual character display conventions. This
section describes how to make, inspect, and assign elements to a
display table object. The next section (see Active Display Table)
describes the various standard display tables and their precedence.
This creates and returns a display table. The table initially has
nil in all elements.
The ordinary elements of the display table are indexed by character
codes; the element at index c says how to display the character
code c. The value should be nil (which means to display
the character c according to the usual display conventions;
see Usual Display Conventions), or a vector of glyph codes (which means to
display the character c as those glyphs; see Glyphs).
Warning: if you use the display table to change the display of newline characters, the whole buffer will be displayed as one long line.
The display table also has six extra slots which serve special
purposes. Here is a table of their meanings; nil in any slot
means to use the default for that slot, as stated below.
The glyph for the end of a truncated screen line (the default for this is ‘$’). See Glyphs. On graphical terminals, Emacs by default uses arrows in the fringes to indicate truncation, so the display table has no effect, unless you disable the fringes (see Window Fringes in the GNU Emacs Manual).
The glyph for the end of a continued line (the default is ‘\’). On graphical terminals, Emacs by default uses curved arrows in the fringes to indicate continuation, so the display table has no effect, unless you disable the fringes.
The glyph for indicating a character displayed as an octal character code (the default is ‘\’).
The glyph for indicating a control character (the default is ‘^’).
A vector of glyphs for indicating the presence of invisible lines (the default is ‘...’). See Selective Display.
The glyph used to draw the border between side-by-side windows (the default is ‘|’). See Splitting Windows. This currently has effect only on text terminals; on graphical terminals, if vertical scroll bars are supported and in use, a scroll bar separates the two windows, and if there are no vertical scroll bars and no dividers (see Window Dividers), Emacs uses a thin line to indicate the border.
For example, here is how to construct a display table that mimics
the effect of setting ctl-arrow to a non-nil value
(see Glyphs, for the function make-glyph-code):
(setq disptab (make-display-table))
(dotimes (i 32)
(or (= i ?\t)
(= i ?\n)
(aset disptab i
(vector (make-glyph-code ?^ 'escape-glyph)
(make-glyph-code (+ i 64) 'escape-glyph)))))
(aset disptab 127
(vector (make-glyph-code ?^ 'escape-glyph)
(make-glyph-code ?? 'escape-glyph)))
This function returns the value of the extra slot slot of
display-table. The argument slot may be a number from 0 to
5 inclusive, or a slot name (symbol). Valid symbols are
truncation, wrap, escape, control,
selective-display, and vertical-border.
This function stores value in the extra slot slot of
display-table. The argument slot may be a number from 0 to
5 inclusive, or a slot name (symbol). Valid symbols are
truncation, wrap, escape, control,
selective-display, and vertical-border.
This function displays a description of the display table display-table in a help buffer.
This command displays a description of the current display table in a help buffer.
Each window can specify a display table, and so can each buffer.
The window’s display table, if there is one, takes precedence over the
buffer’s display table. If neither exists, Emacs tries to use the
standard display table; if that is nil, Emacs uses the usual
character display conventions (see Usual Display Conventions). (Emacs does
not “merge” display tables: For instance, if the window has a
display table, the buffer’s display table and the standard display
table are completely ignored.)
Note that display tables affect how the mode line is displayed, so
if you want to force redisplay of the mode line using a new display
table, call force-mode-line-update (see 模式行格式).
This function returns window’s display table, or nil if
there is none. The default for window is the selected window.
This function sets the display table of window to table.
The argument table should be either a display table or
nil.
This variable is automatically buffer-local in all buffers; its value
specifies the buffer’s display table. If it is nil, there is
no buffer display table.
The value of this variable is the standard display table, which is
used when Emacs is displaying a buffer in a window with neither a
window display table nor a buffer display table defined, or when Emacs
is outputting text to the standard output or error streams. Although its
default is typically nil, in an interactive session if the
terminal cannot display curved quotes, its default maps curved quotes
to ASCII approximations. See 文本引用样式.
The disp-table library defines several functions for changing the standard display table.
A glyph is a graphical symbol which occupies a single character position on the screen. Each glyph is represented in Lisp as a glyph code, which specifies a character and optionally a face to display it in (see Faces). The main use of glyph codes is as the entries of display tables (see Display Tables). The following functions are used to manipulate glyph codes:
This function returns a glyph code representing char char with
face face. If face is omitted or nil, the glyph
uses the default face; in that case, the glyph code is an integer. If
face is non-nil, the glyph code is not necessarily an
integer object.
This function returns the character of glyph code glyph.
This function returns face of glyph code glyph, or nil if
glyph uses the default face.
You can set up a glyph table to change how glyph codes are
actually displayed on text terminals. This feature is semi-obsolete;
use glyphless-char-display instead (see Glyphless Character Display).
The value of this variable, if non-nil, is the current glyph
table. It takes effect only on character terminals; on graphical
displays, all glyphs are displayed literally. The glyph table should
be a vector whose gth element specifies how to display glyph
code g, where g is the glyph code for a glyph whose face
is unspecified. Each element should be one of the following:
nilDisplay this glyph literally.
Display this glyph by sending the specified string to the terminal.
Display the specified glyph code instead.
Any integer glyph code greater than or equal to the length of the glyph table is displayed literally.
Glyphless characters are characters which are displayed in a special way, e.g., as a box containing a hexadecimal code, instead of being displayed literally. These include characters which are explicitly defined to be glyphless, as well as characters for which there is no available font (on a graphical display), and characters which cannot be encoded by the terminal’s coding system (on a text terminal).
The glyphless-display-mode minor mode can be used to toggle
displaying glyphless characters in a convenient manner in the current
buffer. If this mode is enabled, all the glyphless characters are
displayed as boxes that display acronyms of their character names.
For more fine-grained (and global) control, this variable can be used. The value of this variable is a char-table which defines glyphless characters and how they are displayed. Each entry must be one of the following display methods:
nilDisplay the character in the usual way.
zero-widthDon’t display the character.
thin-spaceDisplay a thin space, 1-pixel wide on graphical displays, or 1-character wide on text terminals.
empty-boxDisplay an empty box.
hex-codeDisplay a box containing the Unicode codepoint of the character, in hexadecimal notation.
Display a box containing that string. The string should contain at most 6 ASCII characters. As an exception, if the string includes just one character, on text-mode terminals that character will be displayed without a box; this enables treating such “acronyms” as replacement characters for characters that cannot be displayed by the terminal.
(graphical . text)Display with graphical on graphical displays, and with text on text terminals. Both graphical and text must be one of the display methods described above.
The thin-space, empty-box, hex-code, and
ASCII string display methods are drawn with the
glyphless-char face. On text terminals, a box is emulated by
square brackets, ‘[]’.
The char-table has one extra slot, which determines how to display any
character that cannot be displayed with any available font, or cannot
be encoded by the terminal’s coding system. Its value should be one
of the above display methods, except zero-width.
If a character has a non-nil entry in an active display table,
the display table takes effect; in this case, Emacs does not consult
glyphless-char-display at all.
This user option provides a convenient way to set
glyphless-char-display for groups of similar characters. Do
not set its value directly from Lisp code; the value takes effect only
via a custom :set function (see 定义自定义变量),
which updates glyphless-char-display.
Its value should be an alist of elements (group
. method), where group is a symbol specifying a group of
characters, and method is a symbol specifying how to display
them.
group should be one of the following:
c0-controlASCII control characters U+0000 to U+001F,
excluding the newline and tab characters (normally displayed as escape
sequences like ‘^A’; see How Text Is Displayed in The GNU Emacs Manual).
c1-controlNon-ASCII, non-printing characters U+0080 to
U+009F (normally displayed as octal escape sequences like
‘\230’).
format-controlCharacters of Unicode General Category [Cf], such as U+200E LEFT-TO-RIGHT MARK, but excluding characters that have graphic images, such as U+00AD SOFT HYPHEN.
bidi-controlThis is a subset of format-control, but only includes
characters that are related to bidirectional formatting control, like
U+2069 POP DIRECTIONAL ISOLATE and U+202A LEFT-TO-RIGHT
EMBEDDING. See Bidirectional Display.
Characters of Unicode General Category [Cf], such as U+200E LEFT-TO-RIGHT MARK, but excluding characters that have graphic images, such as U+00AD SOFT HYPHEN.
variation-selectorsUnicode VS-1 through VS-256 (U+FE00 through U+FE0F and U+E0100 through U+E01EF), which are used to select between different glyphs for the same codepoints (typically emojis).
no-fontCharacters for which there is no suitable font, or which cannot be encoded by the terminal’s coding system, or those for which the text-mode terminal has no glyphs.
The method symbol should be one of zero-width,
thin-space, empty-box, or hex-code. These have
the same meanings as in glyphless-char-display, above.
This section describes how to make Emacs ring the bell (or blink the screen) to attract the user’s attention. Be conservative about how often you do this; frequent bells can become irritating. Also be careful not to use just beeping when signaling an error is more appropriate (see 错误).
This function beeps, or flashes the screen (see visible-bell below).
It also terminates any keyboard macro currently executing unless
do-not-terminate is non-nil.
This is a synonym for ding.
This variable determines whether Emacs should flash the screen to
represent a bell. Non-nil means yes, nil means no.
This is effective on graphical displays, and on text terminals
provided the terminal’s Termcap entry defines the visible bell
capability (‘vb’).
If this is non-nil, it specifies how Emacs should ring the
bell. Its value should be a function of no arguments. If this is
non-nil, it takes precedence over the visible-bell
variable.
Emacs works with several window systems, most notably the X Window System. Both Emacs and X use the term “window”, but use it differently. An Emacs frame is a single window as far as X is concerned; the individual Emacs windows are not known to X at all.
This terminal-local variable tells Lisp programs what window system Emacs is using for displaying the frame. The possible values are
x ¶Emacs is displaying the frame using X.
w32Emacs is displaying the frame using native MS-Windows GUI.
nsEmacs is displaying the frame using the Nextstep interface (used on GNUstep and macOS).
pcEmacs is displaying the frame using MS-DOS direct screen writes.
haikuEmacs is displaying the frame using the Application Kit on Haiku.
pgtkEmacs is displaying the frame using pure GTK facilities.
androidEmacs is displaying the frame on Android.
nilEmacs is displaying the frame on a character-based terminal.
This variable holds the value of window-system used for the
first frame created by Emacs during startup. (When Emacs is invoked
as a daemon, it does not create any initial
frames, so initial-window-system is nil, except on
MS-Windows, where it is still w32. See daemon in The GNU Emacs Manual.)
This function returns a symbol whose name tells what window system is
used for displaying frame (which defaults to the currently
selected frame). The list of possible symbols it returns is the same
one documented for the variable window-system above.
Do not use window-system and
initial-window-system as predicates or boolean flag variables,
if you want to write code that works differently on text terminals and
graphic displays. That is because window-system is not a good
indicator of Emacs capabilities on a given display type. Instead, use
display-graphic-p or any of the other display-*-p
predicates described in Display Feature Testing.
Tooltips are special frames (see Frames) that are used to display helpful hints (a.k.a. “tips”) related to the current position of the mouse pointer. Emacs uses tooltips to display help strings about active portions of text (see Properties with Special Meanings) and about various UI elements, such as menu items (see 扩展菜单项) and tool-bar buttons (see 工具栏).
Tooltip Mode is a minor mode that enables display of tooltips. Turning off this mode causes the tooltips be displayed in the echo area. On text-mode (a.k.a. “TTY”) frames, tooltips are always displayed in the echo area.
When Emacs is built with the GTK+ toolkit or Haiku windowing support,
it by default displays tooltips using toolkit functions, and the
appearance of the tooltips is then controlled by the toolkit’s
settings. Toolkit-provided tooltips can be disabled by changing the
value of the variable use-system-tooltips to nil. The
rest of this subsection describes how to control non-toolkit tooltips,
which are presented by Emacs itself.
Tooltips are displayed in special frames called tooltip frames, which have their own frame parameters (see Frame Parameters). Unlike other frames, the default parameters for tooltip frames are stored in a special variable.
This customizable option holds the default frame parameters used for
displaying tooltips. Any font and color parameters are ignored, and the
corresponding attributes of the tooltip face are used instead.
If left or top parameters are included, they are used as
absolute frame-relative coordinates where the tooltip should be shown.
(Mouse-relative position of the tooltip can be customized using the
variables described in Tooltips in The GNU Emacs Manual.)
Note that the left and top parameters, if present,
override the values of mouse-relative offsets.
The tooltip face determines the appearance of text shown in
tooltips. It should generally use a variable-pitch font of size that
is preferably smaller than the default frame font.
This abnormal hook is a list of functions to call when Emacs needs to
display a tooltip. Each function is called with a single argument
event which is a copy of the last mouse movement event. If a
function on this list actually displays the tooltip, it should return
non-nil, and then the rest of the functions will not be
called. The default value of this variable is a single function
tooltip-help-tips.
If you write your own function to be put on the
tooltip-functions list, you may need to know the buffer of the
mouse event that triggered the tooltip display. The following
function provides that information.
This function returns the buffer over which event occurred.
Call it with the argument of the function from
tooltip-functions to obtain the buffer whose text triggered the
tooltip. Note that the event might occur not over a buffer (e.g.,
over the tool bar), in which case this function will return
nil.
Other aspects of tooltip display are controlled by several customizable settings; see Tooltips in The GNU Emacs Manual.
Emacs can display text written in scripts, such as Arabic, Farsi, and Hebrew, whose natural ordering for horizontal text display runs from right to left. Furthermore, segments of Latin script and digits embedded in right-to-left text are displayed left-to-right, while segments of right-to-left script embedded in left-to-right text (e.g., Arabic or Hebrew text in comments or strings in a program source file) are appropriately displayed right-to-left. We call such mixtures of left-to-right and right-to-left text bidirectional text. This section describes the facilities and options for editing and displaying bidirectional text.
Text is stored in Emacs buffers and strings in logical (or reading) order, i.e., the order in which a human would read each character. In right-to-left and bidirectional text, the order in which characters are displayed on the screen (called visual order) is not the same as logical order; the characters’ screen positions do not increase monotonically with string or buffer position. In performing this bidirectional reordering, Emacs follows the Unicode Bidirectional Algorithm (a.k.a. UBA), which is described in Annex #9 of the Unicode standard (https://www.unicode.org/reports/tr9/). Emacs provides a “Full Bidirectionality” class implementation of the UBA, consistent with the requirements of the Unicode Standard v9.0. Note, however, that the way Emacs displays continuation lines when text direction is opposite to the base paragraph direction deviates from the UBA, which requires performing line wrapping before reordering text for display.
If the value of this buffer-local variable is non-nil (the
default), Emacs performs bidirectional reordering for display. The
reordering affects buffer text, as well as display strings and overlay
strings from text and overlay properties in the buffer (see Overlay Properties, and see The display Property). If the value is
nil, Emacs does not perform bidirectional reordering in the
buffer.
The default value of bidi-display-reordering controls the
reordering of strings which are not directly supplied by a buffer,
including the text displayed in mode lines (see 模式行格式)
and header lines (see 窗口标题栏).
Emacs never reorders the text of a unibyte buffer, even if
bidi-display-reordering is non-nil in the buffer. This
is because unibyte buffers contain raw bytes, not characters, and thus
lack the directionality properties required for reordering.
Therefore, to test whether text in a buffer will be reordered for
display, it is not enough to test the value of
bidi-display-reordering alone. The correct test is this:
(if (and enable-multibyte-characters
bidi-display-reordering)
;; Buffer is being reordered for display
)
However, unibyte display and overlay strings are reordered if their parent buffer is reordered. This is because plain-ASCII strings are stored by Emacs as unibyte strings. If a unibyte display or overlay string includes non-ASCII characters, these characters are assumed to have left-to-right direction.
Text covered by display text properties, by overlays with
display properties whose value is a string, and by any other
properties that replace buffer text, is treated as a single unit when
it is reordered for display. That is, the entire chunk of text
covered by these properties is reordered together. Moreover, the
bidirectional properties of the characters in such a chunk of text are
ignored, and Emacs reorders them as if they were replaced with a
single character U+FFFC, known as the Object Replacement
Character. This means that placing a display property over a portion
of text may change the way that the surrounding text is reordered for
display. To prevent this unexpected effect, always place such
properties on text whose directionality is identical with text that
surrounds it.
Each paragraph of bidirectional text has a base direction, either right-to-left or left-to-right. Left-to-right paragraphs are displayed beginning at the left margin of the window, and are truncated or continued when the text reaches the right margin. Right-to-left paragraphs are displayed beginning at the right margin, and are continued or truncated at the left margin.
Where exactly paragraphs start and end, for the purpose of the Emacs
UBA implementation, is determined by the following two
buffer-local variables (note that paragraph-start and
paragraph-separate have no influence on this). By default both
of these variables are nil, and paragraphs are bounded by empty
lines, i.e., lines that consist entirely of zero or more whitespace
characters followed by a newline.
If non-nil, this variable’s value should be a regular
expression matching a line that starts or separates two paragraphs.
The regular expression is always matched after a newline, so it is
best to anchor it, i.e., begin it with a "^".
If non-nil, this variable’s value should be a regular
expression matching a line separates two paragraphs. The regular
expression is always matched after a newline, so it is best to anchor
it, i.e., begin it with a "^".
If you modify any of these two variables, you should normally modify
both, to make sure they describe paragraphs consistently. For
example, to have each new line start a new paragraph for
bidi-reordering purposes, set both variables to "^".
By default, Emacs determines the base direction of each paragraph by looking at the text at its beginning. The precise method of determining the base direction is specified by the UBA; in a nutshell, the first character in a paragraph that has an explicit directionality determines the base direction of the paragraph. However, sometimes a buffer may need to force a certain base direction for its paragraphs. For example, buffers containing program source code should force all paragraphs to be displayed left-to-right. You can use following variable to do this:
If the value of this buffer-local variable is the symbol
right-to-left or left-to-right, all paragraphs in the
buffer are assumed to have that specified direction. Any other value
is equivalent to nil (the default), which means to determine
the base direction of each paragraph from its contents.
Modes for program source code should set this to left-to-right.
Prog mode does this by default, so modes derived from Prog mode do not
need to set this explicitly (see 基础主模式).
This function returns the paragraph direction at point in the named
buffer. The returned value is a symbol, either
left-to-right or right-to-left. If buffer is
omitted or nil, it defaults to the current buffer. If the
buffer-local value of the variable bidi-paragraph-direction is
non-nil, the returned value will be identical to that value;
otherwise, the returned value reflects the paragraph direction
determined dynamically by Emacs. For buffers whose value of
bidi-display-reordering is nil as well as unibyte
buffers, this function always returns left-to-right.
Sometimes there’s a need to move point in strict visual order, either to the left or to the right of its current screen position. Emacs provides a primitive to do that.
This function moves point of the currently selected window to the buffer position that appears immediately to the right or to the left of point on the screen. If direction is positive, point will move one screen position to the right, otherwise it will move one screen position to the left. Note that, depending on the surrounding bidirectional context, this could potentially move point many buffer positions away. If invoked at the end of a screen line, the function moves point to the rightmost or leftmost screen position of the next or previous screen line, as appropriate for the value of direction.
The function returns the new buffer position as its value.
Bidirectional reordering can have surprising and unpleasant effects when two strings with bidirectional content are juxtaposed in a buffer, or otherwise programmatically concatenated into a string of text. A typical problematic case is when a buffer consists of sequences of text fields separated by whitespace or punctuation characters, like Buffer Menu mode or Rmail Summary Mode. Because the punctuation characters used as separators have weak directionality, they take on the directionality of surrounding text. As result, a numeric field that follows a field with bidirectional content can be displayed to the left of the preceding field, messing up the expected layout. There are several ways to avoid this problem:
bidi-string-mark-left-to-right, described below, comes
in handy for this purpose. (In a right-to-left paragraph, use
U+200F RIGHT-TO-LEFT MARK, or RLM, instead.) This
is one of the solutions recommended by the UBA.
display property or overlay with a
property value of the form (space . PROPS) (see Specified Spaces). Emacs treats this display specification as a paragraph
separator, and reorders the text on either side separately.
This function returns its argument string, possibly modified,
such that the result can be safely concatenated with another string,
or juxtaposed with another string in a buffer, without disrupting the
relative layout of this string and the next one on display. If the
string returned by this function is displayed as part of a
left-to-right paragraph, it will always appear on display to the left
of the text that follows it. The function works by examining the
characters of its argument, and if any of those characters could cause
reordering on display, the function appends the LRM
character to the string. The appended LRM character is made
invisible by giving it an invisible text property of t
(see Invisible Text).
The reordering algorithm uses the bidirectional properties of the
characters stored as their bidi-class property
(see Character Properties). Lisp programs can change these
properties by calling the put-char-code-property function.
However, doing this requires a thorough understanding of the
UBA, and is therefore not recommended. Any changes to the
bidirectional properties of a character have global effect: they
affect all Emacs frames and windows.
Similarly, the mirroring property is used to display the
appropriate mirrored character in the reordered text. Lisp programs
can affect the mirrored display by changing this property. Again, any
such changes affect all of Emacs display.
The bidirectional properties of characters can be overridden by inserting into the text special directional control characters, LEFT-TO-RIGHT OVERRIDE (LRO) and RIGHT-TO-LEFT OVERRIDE (RLO). Any characters between a RLO and the following newline or POP DIRECTIONAL FORMATTING (PDF) control character, whichever comes first, will be displayed as if they were strong right-to-left characters, i.e. they will be reversed on display. Similarly, any characters between LRO and PDF or newline will display as if they were strong left-to-right, and will not be reversed even if they are strong right-to-left characters.
These overrides are useful when you want to make some text unaffected by the reordering algorithm, and instead directly control the display order. But they can also be used for malicious purposes, known as phishing. Specifically, a URL on a Web page or a link in an email message can be manipulated to make its visual appearance unrecognizable, or similar to some popular benign location, while the real location, interpreted by a browser in the logical order, is very different.
Emacs provides a primitive that applications can use to detect instances of text whose bidirectional properties were overridden so as to make a left-to-right character display as if it were a right-to-left character, or vice versa.
This function looks at the text of the specified object between
positions from (inclusive) and to (exclusive), and returns
the first position where it finds a strong left-to-right character
whose directional properties were forced to display the character as
right-to-left, or for a strong right-to-left character that was forced
to display as left-to-right. If it finds no such characters in the
specified region of text, it returns nil.
The optional argument object specifies which text to search, and
defaults to the current buffer. If object is non-nil, it
can be some other buffer, or it can be a string or a window. If it is
a string, the function searches that string. If it is a window, the
function searches the buffer displayed in that window. If a buffer
whose text you want to examine is displayed in some window, we
recommend to specify it by that window, rather than pass the buffer to
the function. This is because telling the function about the window
allows it to correctly account for window-specific overlays, which
might change the result of the function if some text in the buffer is
covered by overlays.
When text that includes mixed right-to-left and left-to-right characters and bidirectional controls is copied into a different location, it can change its visual appearance, and also can affect the visual appearance of the surrounding text at destination. This is because reordering of bidirectional text specified by the UBA has non-trivial context-dependent effects both on the copied text and on the text at copy destination that will surround it.
Sometimes, a Lisp program may need to preserve the exact visual appearance of the copied text at destination, and of the text that surrounds the copy. Lisp programs can use the following function to achieve that effect.
This function works similar to buffer-substring (see Examining Buffer Contents), but it prepends and appends to the copied text bidi
directional control characters necessary to preserve the visual
appearance of the text when it is inserted at another place. Optional
argument no-properties, if non-nil, means remove the text
properties from the copy of the text.
This chapter is about starting and getting out of Emacs, access to values in the operating system environment, and terminal input, output.
See Building Emacs, for related information. See Emacs Display, for additional operating system status information pertaining to the terminal and the screen.
This section describes what Emacs does when it is started, and how you can customize these actions.
When Emacs is started up, it performs the following operations
(see normal-top-level in startup.el):
load-path, by running the file named
subdirs.el in each directory in the list. Normally, this file
adds the directory’s subdirectories to the list, and those are scanned
in their turn. The files subdirs.el are normally generated
automatically when Emacs is installed.
load-path
directories. This file is intended for registering input methods.
The search is only for any personal leim-list.el files that you
may have created; it skips the directories containing the standard Emacs
libraries (these should contain only a single leim-list.el file,
which is compiled into the Emacs executable).
before-init-time to the value of
current-time (see Time of Day). It also sets
after-init-time to nil, which signals to Lisp programs
that Emacs is being initialized.
LANG.
package-activate-all to activate any
optional Emacs Lisp package that has been installed. See Packaging Basics. However, Emacs doesn’t activate the packages when
package-enable-at-startup is nil or when it’s started
with one of the options ‘-q’, ‘-Q’, or ‘--batch’. To
activate the packages in the latter case, package-activate-all
should be called explicitly (e.g., via the ‘--funcall’ option).
initial-window-system specifies (see initial-window-system). The initialization function,
window-system-initialization, is a generic function
(see 泛型函数) whose actual implementation is different
for each supported window system. If the value of
initial-window-system is windowsystem, then the
appropriate implementation of the initialization function is defined
in the file term/windowsystem-win.el. This file should
have been compiled into the Emacs executable when it was built.
before-init-hook.
initial-frame-alist and default-frame-alist
(see Initial Frame Parameters) for the graphical frame, by calling the
window-system-initialization function for that window system.
This is not done in batch (noninteractive) or daemon mode.
custom-reevaluate-setting to re-initialize the members
of the list custom-delayed-init-variables. These are any
pre-loaded user options whose default value depends on the run-time,
rather than build-time, context.
See custom-initialize-delay.
inhibit-default-init is non-nil, nor if the options
‘-q’, ‘-Q’, or ‘--batch’ were specified.
abbrev-file-name, if that file exists and can be read
(see abbrev-file-name). This is not done if the
option ‘--batch’ was specified.
after-init-time to the value of
current-time. This variable was set to nil earlier;
setting it to the current time signals that the initialization phase
is over, and, together with before-init-time, provides the
measurement of how long it took.
after-init-hook and
delayed-warnings-hook. The latter shows any warnings emitted
during previous stages of startup, which are automatically delayed.
initial-major-mode.
tty-setup-hook. This is not done
in --batch mode, nor if term-file-prefix is nil.
inhibit-startup-echo-area-message.
--batch was specified.
(substitute-command-keys initial-scratch-message) into that buffer.
initial-buffer-choice is a string, it visits the file (or
directory) with that name. If it is a function, it calls the function
with no arguments and selects the buffer that it returns. If one file
is given as a command line argument, that file is visited and its
buffer displayed alongside initial-buffer-choice. If more than
one file is given, all of the files are visited and the *Buffer
List* buffer is displayed alongside initial-buffer-choice.
emacs-startup-hook.
frame-notice-user-settings, which modifies the
parameters of the selected frame according to whatever the init files
specify.
window-setup-hook. The only difference between this
hook and emacs-startup-hook is that this one runs after the
previously mentioned modifications to the frame parameters.
inhibit-startup-screen or initial-buffer-choice
are non-nil, or if the ‘--no-splash’ or ‘-Q’ command-line
options were specified.
server-start.
(On POSIX systems, if a background daemon was requested, it then
detaches from the controlling terminal.) See Emacs
Server in The GNU Emacs Manual.
emacs-session-restore passing it as argument the ID of the
previous session. See Session Management.
The following options affect some aspects of the startup sequence.
This variable, if non-nil, inhibits the startup screen. In
that case, Emacs typically displays the *scratch* buffer; but
see initial-buffer-choice, below.
Do not set this variable in the init file of a new user, or in a way that affects more than one user, as that would prevent new users from receiving information about copyleft and basic Emacs usage.
inhibit-startup-message and inhibit-splash-screen are
aliases for this variable.
If non-nil, this variable is a string that specifies a file or
directory for Emacs to display after starting up, instead of the
startup screen.
If its value is a function, Emacs calls that function which must
return a buffer which is then displayed.
If its value is t, Emacs displays the *scratch* buffer.
This variable controls the display of the startup echo area message. You can suppress the startup echo area message by adding text with this form to your init file:
(setq inhibit-startup-echo-area-message
"your-login-name")
Emacs explicitly checks for an expression as shown above in your init
file; your login name must appear in the expression as a Lisp string
constant. You can also use the Customize interface. Other methods of
setting inhibit-startup-echo-area-message to the same value do
not inhibit the startup message. This way, you can easily inhibit the
message for yourself if you wish, but thoughtless copying of your init
file will not inhibit the message for someone else.
This variable, if non-nil, should be a string, which is treated
as documentation to be inserted into the *scratch* buffer when
Emacs starts up or when that buffer is recreated. If it is
nil, the *scratch* buffer is empty.
The following command-line options affect some aspects of the startup sequence. See Initial Options in The GNU Emacs Manual.
--no-splashDo not display a splash screen.
--batchRun without an interactive terminal. See Batch Mode.
--daemon--bg-daemon--fg-daemonDo not initialize any display; just start a server. (A “background” daemon automatically runs in the background.)
--no-init-file-qDo not load either the init file, or the default library.
--no-site-fileDo not load the site-start library.
--quick-QEquivalent to ‘-q --no-site-file --no-splash’.
--init-directorySpecify the directory to use when finding the Emacs init files.
When you start Emacs, it normally attempts to load your init file. This is either a file named .emacs or .emacs.el in your home directory, or a file named init.el in a subdirectory named .emacs.d in your home directory.
The command-line switches ‘-q’, ‘-Q’, and ‘-u’
control whether and where to find the init file; ‘-q’ (and the
stronger ‘-Q’) says not to load an init file, while ‘-u
user’ says to load user’s init file instead of yours.
See Entering Emacs in The GNU Emacs Manual. If neither
option is specified, Emacs uses the LOGNAME environment
variable, or the USER (most systems) or USERNAME (MS
systems) variable, to find your home directory and thus your init
file; this way, even if you have su’d, Emacs still loads your own init
file. If those environment variables are absent, though, Emacs uses
your user-id to find your home directory.
Emacs also attempts to load a second init file, called the early init file, if it exists. This is a file named early-init.el in your ~/.emacs.d directory. The difference between the early init file and the regular init file is that the early init file is loaded much earlier during the startup process, so you can use it to customize some things that are initialized before loading the regular init file. For example, you can customize the process of initializing the package system, by setting variables such as package-load-list or package-enable-at-startup. See Package Installation in The GNU Emacs Manual.
An Emacs installation may have a default init file, which is a
Lisp library named default.el. Emacs finds this file through
the standard search path for libraries (see 程序的加载方式). The Emacs distribution does not come with this file; it is
intended for local customizations. If the default init file exists,
it is loaded whenever you start Emacs. But your own personal init
file, if any, is loaded first; if it sets inhibit-default-init
to a non-nil value, then Emacs does not subsequently load the
default.el file. In batch mode, or if you specify ‘-q’
(or ‘-Q’), Emacs loads neither your personal init file nor
the default init file.
Another file for site-customization is site-start.el. Emacs loads this before the user’s init file. You can inhibit the loading of this file with the option ‘--no-site-file’.
This variable specifies the site-customization file to load before the
user’s init file. Its normal value is "site-start". The only
way you can change it with real effect is to do so before dumping
Emacs.
See Init File Examples in The GNU Emacs Manual, for examples of how to make various commonly desired customizations in your .emacs file.
If this variable is non-nil, it prevents Emacs from loading the
default initialization library file. The default value is nil.
This normal hook is run, once, just before loading all the init files (site-start.el, your init file, and default.el). (The only way to change it with real effect is before dumping Emacs.)
This normal hook is run, once, just after loading all the init files (site-start.el, your init file, and default.el), before loading the terminal-specific library (if started on a text terminal) and processing the command-line action arguments.
This normal hook is run, once, just after handling the command line arguments. In batch mode, Emacs does not run this hook.
This normal hook is very similar to emacs-startup-hook.
The only difference is that it runs slightly later, after setting
of the frame parameters. See window-setup-hook.
This variable holds the absolute file name of the user’s init file. If the actual init file loaded is a compiled file, such as .emacs.elc, the value refers to the corresponding source file.
This variable holds the name of the Emacs default directory.
It defaults to ${XDG_CONFIG_HOME-'~/.config'}/emacs/
if that directory exists and ~/.emacs.d/ and ~/.emacs do
not exist,
otherwise to ~/.emacs.d/ on all platforms but MS-DOS.
Here, ${XDG_CONFIG_HOME-'~/.config'}
stands for the value of the environment variable XDG_CONFIG_HOME
if that variable is set, and for ~/.config otherwise.
See How Emacs Finds Your Init File in The GNU Emacs Manual.
Each terminal type can have its own Lisp library that Emacs loads when
run on that type of terminal. The library’s name is constructed by
concatenating the value of the variable term-file-prefix and the
terminal type (specified by the environment variable TERM).
Normally, term-file-prefix has the value "term/";
changing this is not recommended. If there is an entry matching
TERM in the term-file-aliases association list,
Emacs uses the associated value in place of TERM.
Emacs finds the file in the normal manner, by searching the
load-path directories, and trying the ‘.elc’ and
‘.el’ suffixes.
The usual role of a terminal-specific library is to enable special
keys to send sequences that Emacs can recognize. It may also need to
set or add to input-decode-map if the Termcap or Terminfo entry
does not specify all the terminal’s function keys. See Terminal Input.
When the name of the terminal type contains a hyphen or underscore,
and no library is found whose name is identical to the terminal’s
name, Emacs strips from the terminal’s name the last hyphen or
underscore and everything that follows
it, and tries again. This process is repeated until Emacs finds a
matching library, or until there are no more hyphens or underscores in the name
(i.e., there is no terminal-specific library). For example, if the
terminal name is ‘xterm-256color’ and there is no
term/xterm-256color.el library, Emacs tries to load
term/xterm.el. If necessary, the terminal library can evaluate
(getenv "TERM") to find the full name of the terminal type.
Your init file can prevent the loading of the terminal-specific
library by setting the variable term-file-prefix to nil.
You can also arrange to override some of the actions of the
terminal-specific library by using tty-setup-hook. This is
a normal hook that Emacs runs after initializing a new text terminal.
You could use this hook to define initializations for terminals that do not
have their own libraries. See 钩子.
If the value of this variable is non-nil, Emacs loads a
terminal-specific initialization file as follows:
(load (concat term-file-prefix (getenv "TERM")))
You may set the term-file-prefix variable to nil in your
init file if you do not wish to load the
terminal-initialization file.
On MS-DOS, Emacs sets the TERM environment variable to ‘internal’.
This variable is an association list mapping terminal types to
their aliases. For example, an element of the form ("vt102"
. "vt100") means to treat a terminal of type ‘vt102’ like one of
type ‘vt100’.
This variable is a normal hook that Emacs runs after initializing a
new text terminal. (This applies when Emacs starts up in non-windowed
mode, and when making a tty emacsclient connection.) The
hook runs after loading your init file (if applicable) and the
terminal-specific Lisp file, so you can use it to adjust the
definitions made by that file.
For a related feature, see window-setup-hook.
You can use command-line arguments to request various actions when you start Emacs. Note that the recommended way of using Emacs is to start it just once, after logging in, and then do all editing in the same Emacs session (see Entering Emacs in The GNU Emacs Manual). For this reason, you might not use command-line arguments very often; nonetheless, they can be useful when invoking Emacs from session scripts or debugging Emacs. This section describes how Emacs processes command-line arguments.
This function parses the command line that Emacs was called with, processes it, and (amongst other things) loads the user’s init file and displays the startup messages.
The value of this variable is t once the command line has been
processed.
If you redump Emacs by calling dump-emacs (see Building Emacs), you may wish to set this variable to nil first in
order to cause the new dumped Emacs to process its new command-line
arguments.
This variable is an alist of user-defined command-line options and associated handler functions. By default it is empty, but you can add elements if you wish.
A command-line option is an argument on the command line, which has the form:
-option
The elements of the command-switch-alist look like this:
(option . handler-function)
The CAR, option, is a string, the name of a command-line option (including the initial hyphen). The handler-function is called to handle option, and receives the option name as its sole argument.
In some cases, the option is followed in the command line by an
argument. In these cases, the handler-function can find all the
remaining command-line arguments in the variable
command-line-args-left (see below). (The entire list of
command-line arguments is in command-line-args.)
Note that the handling of command-switch-alist doesn’t treat
equals signs in option specially. That is, if there’s an option
like --name=value on the command line, then only a
command-switch-alist member whose car is literally
--name=value will match this option. If you want to parse such
options, you need to use command-line-functions instead (see
below).
The command-line arguments are parsed by the command-line-1
function in the startup.el file. See also Command Line Arguments for Emacs Invocation in The
GNU Emacs Manual.
The value of this variable is the list of command-line arguments passed to Emacs.
The value of this variable is the list of command-line arguments that have not yet been processed.
This variable’s value is a list of functions for handling an
unrecognized command-line argument. Each time the next argument to be
processed has no special meaning, the functions in this list are called,
in order of appearance, until one of them returns a non-nil
value.
These functions are called with no arguments. They can access the
command-line argument under consideration through the variable
argi, which is bound temporarily at this point. The remaining
arguments (not including the current one) are in the variable
command-line-args-left.
When a function recognizes and processes the argument in argi, it
should return a non-nil value to say it has dealt with that
argument. If it has also dealt with some of the following arguments, it
can indicate that by deleting them from command-line-args-left.
If all of these functions return nil, then the argument is treated
as a file name to visit.
There are two ways to get out of Emacs: you can kill the Emacs job, which exits permanently, or you can suspend it, which permits you to reenter the Emacs process later. (In a graphical environment, you can of course simply switch to another application without doing anything special to Emacs, then switch back to Emacs when you want.)
Killing Emacs means ending the execution of the Emacs process.
If you started Emacs from a terminal, the parent process normally
resumes control. The low-level primitive for killing Emacs is
kill-emacs.
This command calls the hook kill-emacs-hook, then exits the
Emacs process and kills it.
If exit-data is an integer, that is used as the exit status of the Emacs process. (This is useful primarily in batch operation; see Batch Mode.)
If exit-data is a string, its contents are stuffed into the terminal input buffer so that the shell (or whatever program next reads input) can read them.
If exit-data is neither an integer nor a string, or is omitted, that means to use the (system-specific) exit status which indicates successful program termination.
If restart is non-nil, instead of just exiting at the
end, start a new Emacs process, using the same command line arguments
as the currently running Emacs process.
The kill-emacs function is normally called via the
higher-level command C-x C-c
(save-buffers-kill-terminal). See Exiting in The GNU
Emacs Manual. It is also called automatically if Emacs receives a
SIGTERM or SIGHUP operating system signal (e.g., when the
controlling terminal is disconnected), or if it receives a
SIGINT signal while running in batch mode (see Batch Mode).
This normal hook is run by kill-emacs, before it kills Emacs.
Because kill-emacs can be called in situations where user
interaction is impossible (e.g., when the terminal is disconnected),
functions on this hook should not attempt to interact with the user.
If you want to interact with the user when Emacs is shutting down, use
kill-emacs-query-functions, described below.
When Emacs is killed, all the information in the Emacs process,
aside from files that have been saved, is lost. Because killing Emacs
inadvertently can lose a lot of work, the
save-buffers-kill-terminal command queries for confirmation if
you have buffers that need saving or subprocesses that are running.
It also runs the abnormal hook kill-emacs-query-functions:
When save-buffers-kill-terminal is killing Emacs, it calls the
functions in this hook, after asking the standard questions and before
calling kill-emacs. The functions are called in order of
appearance, with no arguments. Each function can ask for additional
confirmation from the user. If any of them returns nil,
save-buffers-kill-emacs does not kill Emacs, and does not run
the remaining functions in this hook. Calling kill-emacs
directly does not run this hook.
This command does the same as save-buffers-kill-emacs, but
instead of just killing the current Emacs process at the end, it’ll
restart a new Emacs process, using the same command line arguments as
the currently running Emacs process.
On text terminals, it is possible to suspend Emacs, which
means stopping Emacs temporarily and returning control to its superior
process, which is usually the shell. This allows you to resume
editing later in the same Emacs process, with the same buffers, the
same kill ring, the same undo history, and so on. To resume Emacs,
use the appropriate command in the parent shell—most likely
fg.
Suspending works only on a terminal device from which the Emacs session was started. We call that device the controlling terminal of the session. Suspending is not allowed if the controlling terminal is a graphical terminal. Suspending is usually not relevant in graphical environments, since you can simply switch to another application without doing anything special to Emacs.
Some operating systems (those without SIGTSTP, or MS-DOS) do
not support suspension of jobs; on these systems, suspension
actually creates a new shell temporarily as a subprocess of Emacs.
Then you would exit the shell to return to Emacs.
This function stops Emacs and returns control to the superior process.
If and when the superior process resumes Emacs, suspend-emacs
returns nil to its caller in Lisp.
This function works only on the controlling terminal of the Emacs
session; to relinquish control of other tty devices, use
suspend-tty (see below). If the Emacs session uses more than
one terminal, you must delete the frames on all the other terminals
before suspending Emacs, or this function signals an error.
See Multiple Terminals.
If string is non-nil, its characters are sent to Emacs’s
superior shell, to be read as terminal input.
Before suspending, suspend-emacs runs the normal hook
suspend-hook. After the user resumes Emacs,
suspend-emacs runs the normal hook suspend-resume-hook.
See 钩子.
The next redisplay after resumption will redraw the entire screen,
unless the variable no-redraw-on-reenter is non-nil.
See Refreshing the Screen.
Here is an example of how you could use these hooks:
(add-hook 'suspend-hook
(lambda () (or (y-or-n-p "Really suspend?")
(error "Suspend canceled"))))
(add-hook 'suspend-resume-hook (lambda () (message "Resumed!")
(sit-for 2)))
Here is what you would see upon evaluating (suspend-emacs "pwd"):
---------- Buffer: Minibuffer ---------- Really suspend? y ---------- Buffer: Minibuffer ----------
---------- Parent Shell ---------- bash$ pwd /home/username bash$ fg
---------- Echo Area ---------- Resumed!
Note that on some operating systems, sending string to the Emacs parent shell might require special privileges, in which case it might silently fail to send string to the shell for execution. On other systems this is not supported, and Emacs will signal an error if you try. Also, string might not be echoed, even if it is executed by the shell. So we don’t recommend relying on this feature in portable Lisp programs.
This variable is a normal hook that Emacs runs before suspending.
This variable is a normal hook that Emacs runs on resuming after a suspension.
If tty specifies a terminal device used by Emacs, this function
relinquishes the device and restores it to its prior state. Frames
that used the device continue to exist, but are not updated and Emacs
doesn’t read input from them. tty can be a terminal object, a
frame (meaning the terminal for that frame), or nil (meaning
the terminal for the selected frame). See Multiple Terminals.
If tty is already suspended, this function does nothing.
This function runs the hook suspend-tty-functions, passing the
terminal object as an argument to each function.
This function resumes the previously suspended terminal device
tty; where tty has the same possible values as it does
for suspend-tty.
This function reopens the terminal device, re-initializes it, and
redraws it with that terminal’s selected frame. It then runs the
hook resume-tty-functions, passing the terminal object as an
argument to each function.
If the same device is already used by another Emacs terminal, this function signals an error. If tty is not suspended, this function does nothing.
This function returns non-nil if tty is the
controlling terminal of the Emacs session; tty can be a
terminal object, a frame (meaning the terminal for that frame), or
nil (meaning the terminal for the selected frame).
This command suspends a frame. For GUI frames, it calls
iconify-frame (see Visibility of Frames); for frames on
text terminals, it calls either suspend-emacs or
suspend-tty, depending on whether the frame is displayed on the
controlling terminal device or not.
Emacs provides access to variables in the operating system environment through various functions. These variables include the name of the system, the user’s UID, and so on.
This variable holds the standard GNU configuration name for the hardware/software configuration of your system, as a string. For example, a typical value for a 64-bit GNU/Linux system is ‘"x86_64-unknown-linux-gnu"’.
The value of this variable is a symbol indicating the type of operating system Emacs is running on. The possible values are:
aixIBM’s AIX.
berkeley-unixBerkeley BSD and its variants.
cygwinCygwin, a POSIX layer on top of MS-Windows.
darwinDarwin (macOS).
gnuThe GNU system (using the GNU kernel, which consists of the HURD and Mach).
gnu/linuxA GNU/Linux system—that is, a variant GNU system, using the Linux kernel. (These systems are the ones people often call “Linux”, but actually Linux is just the kernel, not the whole system.)
gnu/kfreebsdA GNU (glibc-based) system with a FreeBSD kernel.
haikuThe Haiku operating system, a derivative of the Be Operating System.
hpuxHewlett-Packard HPUX operating system.
naclGoogle Native Client (NaCl) sandboxing system.
androidThe Open Handset Alliance’s Android operating system.
ms-dosMicrosoft’s DOS. Emacs compiled with DJGPP for MS-DOS binds
system-type to ms-dos even when you run it on MS-Windows.
usg-unix-vAT&T Unix System V.
windows-ntMicrosoft Windows NT, 9X and later. The value of system-type
is always windows-nt, e.g., even on Windows 10.
We do not wish to add new symbols to make finer distinctions unless it
is absolutely necessary! In fact, we hope to eliminate some of these
alternatives in the future. If you need to make a finer distinction
than system-type allows for, you can test
system-configuration, e.g., against a regexp.
This function returns the name of the machine you are running on, as a string.
If this variable is non-nil, it is used instead of
system-name for purposes of generating email addresses. For
example, it is used when constructing the default value of
user-mail-address. See User Identification.
This function returns the value of the environment variable var,
as a string. var should be a string. If var is undefined
in the environment, getenv returns nil. It returns
‘""’ if var is set but null. Within Emacs, a list of environment
variables and their values is kept in the variable process-environment.
(getenv "USER")
⇒ "lewis"
The shell command printenv prints all or part of the environment:
bash$ printenv PATH=/usr/local/bin:/usr/bin:/bin USER=lewis
TERM=xterm SHELL=/bin/bash HOME=/home/lewis
...
This command sets the value of the environment variable named
variable to value. variable should be a string.
Internally, Emacs Lisp can handle any string. However, normally
variable should be a valid shell identifier, that is, a sequence
of letters, digits and underscores, starting with a letter or
underscore. Otherwise, errors may occur if subprocesses of Emacs try
to access the value of variable. If value is omitted or
nil (or, interactively, with a prefix argument), setenv
removes variable from the environment. Otherwise, value
should be a string.
If the optional argument substitute is non-nil, Emacs
calls the function substitute-env-vars to expand any
environment variables in value.
setenv works by modifying process-environment; binding
that variable with let is also reasonable practice.
setenv returns the new value of variable, or nil
if it removed variable from the environment.
This macro sets the environment variables according to variables
temporarily when executing body. The previous values are
restored when the form finishes. The argument variables should
be a list of pairs of strings of the form
(var value), where var is the name of the
environment variable and value is that variable’s value.
(with-environment-variables (("LANG" "C")
("LANGUAGE" "en_US:en"))
(call-process "ls" nil t))
This variable is a list of strings, each describing one environment
variable. The functions getenv and setenv work by means
of this variable.
process-environment
⇒ ("PATH=/usr/local/bin:/usr/bin:/bin"
"USER=lewis"
"TERM=xterm"
"SHELL=/bin/bash"
"HOME=/home/lewis"
...)
If process-environment contains multiple elements that
specify the same environment variable, the first of these elements
specifies the variable, and the others are ignored.
This variable holds the list of environment variables Emacs inherited from its parent process when Emacs started.
This variable holds a string that says which character separates
directories in a search path (as found in an environment variable). Its
value is ":" for Unix and GNU systems, and ";" for MS systems.
This function returns the connection-local value of variable
path-separator. That is ";" for MS systems and a local
default-directory, and ":" for Unix and GNU systems, or
a remote default-directory.
This function takes a search path string such as the value of
the PATH environment variable, and splits it at the separators,
returning a list of directories. nil in this list means
the current directory. Although the function’s name says
“colon”, it actually uses the value of variable path-separator.
(parse-colon-path ":/foo:/bar")
⇒ (nil "/foo/" "/bar/")
This variable holds the program name under which Emacs was invoked. The value is a string, and does not include a directory name.
This variable holds the directory in which the Emacs executable was
located when it was run, or nil if that directory cannot be
determined.
If non-nil, this is a directory within which to look for the
lib-src and etc subdirectories. In an installed Emacs,
it is normally nil. It is non-nil
when Emacs can’t find those directories in their standard installed
locations, but can find them in a directory related somehow to the one
containing the Emacs executable (i.e., invocation-directory).
This function returns the current 1-minute, 5-minute, and 15-minute system load averages, in a list. The load average indicates the number of processes trying to run on the system.
By default, the values are integers that are 100 times the system load
averages, but if use-float is non-nil, then they are
returned as floating-point numbers without multiplying by 100.
If it is impossible to obtain the load average, this function signals an error. On some platforms, access to load averages requires installing Emacs as setuid or setgid so that it can read kernel information, and that usually isn’t advisable.
If the 1-minute load average is available, but the 5- or 15-minute averages are not, this function returns a shortened list containing the available averages.
(load-average)
⇒ (169 48 36)
(load-average t)
⇒ (1.69 0.48 0.36)
The shell command uptime returns similar information.
This function returns the process ID of the Emacs process, as an integer.
This variable holds the erase character that was selected in the system’s terminal driver, before Emacs was started.
This variable holds the system null device. Its value is
"/dev/null" for Unix and GNU systems, and "NUL" for MS
systems.
This function returns the connection-local value of variable
null-device. That is "NUL" for MS systems and a local
default-directory, and "/dev/null" for Unix and GNU
systems, or a remote default-directory.
This variable says which user’s init files should be used by
Emacs—or nil if none. "" stands for the user who
originally logged in. The value reflects command-line options such as
‘-q’ or ‘-u user’.
Lisp packages that load files of customizations, or any other sort of
user profile, should obey this variable in deciding where to find it.
They should load the profile of the user name found in this variable.
If init-file-user is nil, meaning that the ‘-q’,
‘-Q’, or ‘-batch’ option was used, then Lisp packages should
not load any customization files or user profile.
This holds the email address of the user who is using Emacs.
This function returns the name under which the user is logged in.
It uses the environment variables LOGNAME or USER if
either is set. Otherwise, the value is based on the effective
UID, not the real UID.
If you specify uid (a number), the result is the user name that
corresponds to uid, or nil if there is no such user.
This function returns the user name corresponding to Emacs’s real
UID. This ignores the effective UID, and the
environment variables LOGNAME and USER.
This function returns the full name of the logged-in user—or the value
of the environment variable NAME, if that is set.
If the Emacs process’s user-id does not correspond to any known user (and
provided NAME is not set), the result is "unknown".
If uid is non-nil, then it should be a number (a user-id)
or a string (a login name). Then user-full-name returns the full
name corresponding to that user-id or login name. If you specify a
user-id or login name that isn’t defined, it returns nil.
The symbols user-login-name, user-real-login-name and
user-full-name are variables as well as functions. The functions
return the same values that the variables hold. These variables allow
you to fake out Emacs by telling the functions what to return. The
variables are also useful for constructing frame titles (see Frame Titles).
This function returns the real UID of the user.
This function returns the effective UID of the user.
This function returns the connection-local value for the user’s
effective UID. If default-directory is local, this
is equivalent to user-uid, but for remote files (see Remote
Files in The GNU Emacs Manual), it will return the
UID for the user associated with that remote connection; if
the remote connection has no associated user, it will instead return
-1.
This function returns the real GID of the Emacs process.
This function returns the effective GID of the Emacs process.
This function returns the connection-local value for the user’s
effective GID. Similar to file-user-uid, if
default-directory is local, this is equivalent to
group-gid, but for remote files (see Remote Files in The GNU Emacs Manual), it will return the GID for
the user associated with that remote connection; if the remote
connection has no associated user, it will instead return -1.
This function returns a list of strings, listing the user names on the
system. If Emacs cannot retrieve this information, the return value
is a list containing just the value of user-real-login-name.
This function returns a list of strings, listing the names of user
groups on the system. If Emacs cannot retrieve this information, the
return value is nil.
This function returns the group name that corresponds to the numeric
group ID gid, or nil if there is no such group.
This section explains how to determine the current time and time zone.
Many functions like current-time and file-attributes
return Lisp timestamp values that count seconds, and that can
represent absolute time by counting seconds since the epoch of
1970-01-01 00:00:00 UTC (Coordinated Universal Time). Typically these
counts ignore leap seconds; however, GNU and some other operating
systems can be configured to count leap seconds.
Although traditionally Lisp timestamps were integer pairs, their
form has evolved and programs ordinarily should not depend on the
current default form. If your program needs a particular timestamp
form, you can use the time-convert function to convert it to the
needed form. See Time Conversion.
There are currently three forms of Lisp timestamps, each of which represents a number of seconds:
(ticks . hz), where hz is
positive. This represents ticks/hz seconds, which is the
same time as plain ticks if hz is 1. A common value for
hz is 1000000000, for a nanosecond-resolution
clock.
(high low micro
pico), where 0≤low<65536,
0≤micro<1000000, and 0≤pico<1000000.
This represents the number of seconds using the formula:
high * 2**16 + low + micro * 10**−6 +
pico * 10**−12.
If current-time-list is t,
some functions may default to returning two- or
three-element lists, with omitted micro and pico
components defaulting to zero.
On all current machines pico is a multiple of 1000, but this
may change as higher-resolution clocks become available.
Function arguments, e.g., the time argument to
format-time-string, accept a more-general time value
format, which can be a Lisp timestamp, nil for the current
time, a finite floating-point number for seconds, or a list
(high low micro) or (high
low) that is a truncated list timestamp with missing elements
taken to be zero.
Time values can be converted to and from calendrical and other forms.
Some of these conversions rely on operating system functions that
limit the range of possible time values, and signal an error such as
‘"Specified time is not representable"’ if the
limits are exceeded. For instance, a system might not support
timestamps before the epoch, or years far in the future.
You can convert a time value into
a human-readable string using format-time-string, into a Lisp
timestamp using time-convert, and into other forms using
decode-time and float-time. These functions are
described in the following sections.
This function returns the current time and date as a human-readable
string. The format does not vary for the initial part of the string,
which contains the day of week, month, day of month, and time of day
in that order: the number of characters used for these fields is
always the same, although (unless you require English weekday or
month abbreviations regardless of locale) it is typically more
convenient to use format-time-string than to extract
fields from the output of current-time-string,
as the year might not have exactly four digits, and additional
information may some day be added at the end.
The argument time, if given, specifies a time to format, instead of the current time. The optional argument zone defaults to the current time zone rule. See Time Zone Rules. The operating system limits the range of time and zone values.
(current-time-string)
⇒ "Fri Nov 1 15:59:49 2019"
This boolean variable is a transition aid. If t,
current-time and related functions return timestamps in list
form, typically (high low micro pico);
otherwise, they use (ticks . hz) form. Currently
this variable defaults to t, for behavior compatible with
previous Emacs versions. Developers are encouraged to test
timestamp-related code with this variable set to nil, as it
will default to nil in a future Emacs version, and will be
removed in some version after that.
This function returns the current time as a Lisp timestamp.
If current-time-list is nil,
the timestamp has the form (ticks . hz) where
ticks counts clock ticks and hz is the clock ticks per second.
Otherwise, the timestamp has the list form
(high low usec psec).
You can use (time-convert nil t) or (time-convert nil 'list)
to obtain a particular form regardless of the value of
current-time-list. See Time Conversion.
This function returns the current time as a floating-point number of seconds since the epoch. The optional argument time, if given, specifies a time to convert instead of the current time.
Warning: Since the result is floating point, it may not be
exact. Do not use this function if precise time stamps are required.
For example, on typical systems (float-time '(1 . 10)) displays
as ‘0.1’ but is slightly greater than 1/10.
time-to-seconds is an alias for this function.
Return the current CPU time along with its resolution. The
return value is a pair (CPU-TICKS . TICKS-PER-SEC). The
CPU-TICKS counter can wrap around, so values cannot be
meaningfully compared if too much time has passed between them.
The default time zone is determined by the TZ environment
variable. See Operating System Environment. For example, you can tell Emacs
to default to Universal Time with (setenv "TZ" "UTC0"). If
TZ is not in the environment, Emacs uses system wall clock time,
which is a platform-dependent default time zone.
The set of supported TZ strings is system-dependent. GNU and
many other systems support TZDB timezones, e.g.,
‘"America/New_York"’ specifies the time zone and daylight saving
time history for locations near New York City. GNU and most other
systems support POSIX-style TZ strings, e.g.,
‘"EST5EDT,M4.1.0,M10.5.0"’ specifies the rules used in New
York from 1987 through 2006. All systems support the string
‘"UTC0"’ meaning Universal Time.
Functions that convert to and from local time accept an optional
time zone rule argument, which specifies the conversion’s time
zone and daylight saving time history. If the time zone rule is
omitted or nil, the conversion uses Emacs’s default time zone.
If it is t, the conversion uses Universal Time. If it is
wall, the conversion uses the system wall clock time. If it is
a string, the conversion uses the time zone rule equivalent to setting
TZ to that string. If it is a list (offset abbr), where
offset is an integer number of seconds east of Universal Time
and abbr is a string, the conversion uses a fixed time zone with
the given offset and abbreviation. An integer offset is treated
as if it were (offset abbr), where abbr is a numeric
abbreviation on POSIX-compatible platforms and is unspecified on
MS-Windows.
This function returns a list describing the time zone that the user is in.
The value has the form (offset abbr). Here
offset is an integer giving the number of seconds ahead of Universal Time
(east of Greenwich). A negative value means west of Greenwich. The
second element, abbr, is a string giving an abbreviation for the
time zone, e.g., ‘"CST"’ for China Standard Time or for
U.S. Central Standard Time. Both elements can change when daylight
saving time begins or ends; if the user has specified a time zone that
does not use a seasonal time adjustment, then the value is constant
through time.
If the operating system doesn’t supply all the information necessary to
compute the value, the unknown elements of the list are nil.
The argument time, if given, specifies a time value to analyze instead of the current time. The optional argument zone defaults to the current time zone rule. The operating system limits the range of time and zone values.
These functions convert time values (see Time of Day) to Lisp timestamps, or into calendrical information and vice versa.
Many operating systems use 64-bit signed integers to count seconds, and can represent times far in the past or future. However, some are more limited. For example, old-fashioned operating systems that use 32-bit signed integers typically handle only times from 1901-12-13 20:45:52 through 2038-01-19 03:14:07 Universal Time.
Calendrical conversion functions use the Gregorian calendar even for dates before the Gregorian calendar was introduced, and for dates in the far distant past or future for which the Gregorian calendar is wildly inaccurate and disagrees with common practice in scientific fields like astronomy and paleontology, which use Julian-calendar year lengths. Year numbers count since the year 1 BCE, and do not skip zero as traditional Gregorian years do; for example, the year number −37 represents the Gregorian year 38 BCE.
This function converts a time value into a Lisp timestamp.
The form argument specifies the timestamp form to be returned.
If form is the symbol integer, this function returns an
integer count of seconds. If form is a positive integer, it
specifies a clock frequency and this function returns an integer-pair
timestamp (ticks . form). If form is
t, this function treats it as a positive integer suitable for
representing the timestamp; for example, it is treated as 1000000000
if time is nil and the platform timestamp has nanosecond
resolution. If form is list, this function returns an
integer list (high low micro pico).
Although a nil form currently acts like
list, this is planned to change in a future Emacs version, so
callers requiring list timestamps should pass list explicitly.
If time is not a time value, this function signals an error.
Otherwise, if time cannot be represented exactly, conversion
truncates it toward minus infinity. When form is t,
conversion is always exact so no truncation occurs, and the returned
clock resolution is no less than that of time. By way of
contrast, although float-time can also convert any time value
without signaling an error, the result might not be exact.
See Time of Day.
For efficiency this function might return a value that is eq to
time, or that otherwise shares structure with time.
Although (time-convert nil nil) is equivalent to
(current-time), the latter may be a bit faster.
(setq a (time-convert nil t)) ⇒ (1564826753904873156 . 1000000000)
(time-convert a 100000) ⇒ (156482675390487 . 100000)
(time-convert a 'integer) ⇒ 1564826753
(time-convert a 'list) ⇒ (23877 23681 904873 156000)
This function converts a time value into calendrical information. If you don’t specify time, it decodes the current time, and similarly zone defaults to the current time zone rule. See Time Zone Rules. The operating system limits the range of time and zone values.
The form argument controls the form of the returned seconds element, as described below. The return value is a list of nine elements, as follows:
(seconds minutes hour day month year dow dst utcoff)
Here is what the elements mean:
The number of seconds past the minute, with form described below.
The number of minutes past the hour, as an integer between 0 and 59.
The hour of the day, as an integer between 0 and 23.
The day of the month, as an integer between 1 and 31.
The month of the year, as an integer between 1 and 12.
The year, an integer typically greater than 1900.
The day of week, as an integer between 0 and 6, where 0 stands for Sunday.
t if daylight saving time is effect, nil if it is not
in effect, and −1 if this information is not available.
An integer indicating the Universal Time offset in seconds, i.e., the number of seconds east of Greenwich.
The seconds element is a Lisp timestamp that is nonnegative and
less than 61; it is less than 60 except during positive leap seconds
(assuming the operating system supports leap seconds). If the
optional form argument is t, seconds uses the same
precision as time; if form is integer,
seconds is truncated to an integer. For example, if time
is the timestamp (1566009571321 . 1000), which represents
2019-08-17 02:39:31.321 UTC on typical systems that lack leap seconds,
then (decode-time time t t) returns ((31321 . 1000)
39 2 17 8 2019 6 nil 0), whereas (decode-time time t
'integer) returns (31 39 2 17 8 2019 6 nil 0). If form
is omitted or nil, it currently defaults to integer but
this default may change in future Emacs releases, so callers requiring
a particular form should specify form.
Common Lisp Note: Common Lisp has different meanings for
dow, dst and utcoff, and its second is an
integer between 0 and 59 inclusive.
To access (or alter) the elements in the calendrical information, the
decoded-time-second, decoded-time-minute,
decoded-time-hour, decoded-time-day,
decoded-time-month, decoded-time-year,
decoded-time-weekday, decoded-time-dst and
decoded-time-zone accessors can be used.
This function converts time to a Lisp timestamp.
It can act as the inverse of decode-time.
Ordinarily the first argument is a list
(second minute hour day month
year ignored dst zone) that specifies a
decoded time in the style of decode-time. For the meanings of
these list elements, see the table under decode-time.
In particular, dst says how to interpret timestamps during a
daylight saving fallback when timestamps are repeated.
If dst is −1, the DST value is guessed; if it
is t or nil the timestamp with that DST value
is returned, with an error signaled if no such timestamp exists.
Unfortunately a dst value of t or nil does not
disambiguate timestamps duplicated when a TZDB-based timezone moves
further west of Greenwich, such as disambiguating the two
standard-time timestamps 2020-12-27 01:30 when zone is
‘"Europe/Volgograd"’, which at 02:00 that day changed
standard time from 4 to 3 hours east of Greenwich; if you need to
handle situations like this you can use a numeric zone to
disambiguate instead.
The first argument can also be a list (second minute
hour day month year), which is treated like
the list (second minute hour day
month year nil -1 nil).
As an obsolescent calling convention, this function can be given six
or more arguments. The first six arguments second,
minute, hour, day, month, and year
specify most of the components of a decoded time. If there are more
than six arguments the last argument is used as zone and
any other extra arguments are ignored, so that (apply
#'encode-time (decode-time ...)) works. In this obsolescent
convention, dst is −1 and zone defaults to the
current time zone rule (see Time Zone Rules).
When modernizing an obsolescent caller, ensure that the more-modern
list equivalent contains 9 elements with a dst element that
is −1, not nil.
Year numbers less than 100 are not treated specially. If you want them
to stand for years above 1900, or years above 2000, you must alter them
yourself before you call encode-time.
The operating system limits the range of time and zone values.
However, timestamps ranging from the epoch to the near future are
always supported.
The encode-time function acts as a rough inverse to
decode-time. For example, you can pass the output of
the latter to the former as follows:
(encode-time (decode-time ...))
You can perform simple date arithmetic by using out-of-range values for seconds, minutes, hour, day, and month; for example, day 0 means the day preceding the given month. Take care when doing so, as it is common for this to fail in some cases. For example:
;; Try to compute the time one month from now.
;; Watch out; this might not work as expected.
(let ((time (decode-time)))
(setf (decoded-time-month time)
(+ (decoded-time-month time) 1))
time)
Unfortunately, this code might not work as expected if the resulting
time is invalid due to month length differences,
daylight saving transitions, time zone changes,
or missing leap days or leap seconds. For example, if executed on
January 30 this code yields a nonexistent date February 30,
which encode-time would adjust to early March.
Similarly, adding four years to February 29, 2096 would yield the
nonexistent date February 29, 2100; and adding one hour to 01:30 on
March 13, 2022 in New York would yield a timestamp 02:30 that does not
exist because clocks sprang forward from 02:00 to 03:00 that day.
To avoid some (though not all) of the problem, you
can base calculations on the middle of the affected unit, e.g., start
at the 15th of the month when adding months. Alternatively, you can use the
calendar and time-date libraries.
These functions convert time values to text in a string, and vice versa. Time values are either represented as a Lisp timestamp (see Time of Day) or a decoded time structure (see Time Conversion).
This function parses the time-string string and returns the
corresponding Lisp timestamp. The argument string should represent
a date-time, and should be in one of the forms recognized by
parse-time-string (see below). This function assumes Universal
Time if string lacks explicit time zone information,
and assumes earliest values if string lacks month, day, or time.
The operating system limits the range of time and zone values.
This function parses the time-string string into a decoded time structure (see Time Conversion). The argument string should resemble an RFC 822 (or later) or ISO 8601 string, like “Fri, 25 Mar 2016 16:24:56 +0100” or “1998-09-12T12:21:54-0200”, but this function will attempt to parse less well-formed time strings as well.
Note that, unlike decode-time (see Time Conversion), this
function does not interpret the time string, and in particular the
values of daylight-saving and timezone or UTC offset parts of the
string argument do not affect the returned value of date and time,
they only affect the last two members of the returned decoded time
structure. For example, if the time-zone information is present in
string, the decoded time structure will include it; otherwise the
time-zone member of the returned value will be nil. In other
words, this function simply parses the textual representation of date
and time into separate numerical values, and doesn’t care whether the
input time is local or UTC.
If a Lisp program passes the return value of this function to some other
time-related API, it should make sure the nil members of the
decoded time structure are interpreted correctly, and in particular the
lack of time-zone information is interpreted as UTC or local time,
according to the needs of the calling program.
For a more strict function (that will error out upon invalid input),
Lisp programs can use this function instead. It can parse all variants
of the ISO 8601 standard, so in addition to the formats mentioned above,
it also parses things like “1998W45-3” (week number) and “1998-245”
(ordinal day number). To parse durations, there’s
iso8601-parse-duration, and to parse intervals, there’s
iso8601-parse-interval. All these functions return decoded time
structures, except the final one, which returns three of them (the
start, the end, and the duration).
Like parse-time-string, this function does not interpret the time
string, and in particular the time-zone designator or UTC offset that is
part of the string argument does not affect the returned value of
date and time, it only affects the last two members of the returned
decoded time structure. The ISO 8601 standard specifies that date/time
strings that do not include information about UTC relation are assumed
to be in local time, but this function does not do that, because it
doesn’t interpret the time values. For example, if the time-zone
information is present in string, the decoded time structure will
include it; otherwise the time-zone member of the returned value will be
nil. In other words, this function simply parses the textual
representation of date and time into separate numerical values, and
doesn’t care whether the input time is local or UTC.
This function converts time (which should be a Lisp timestamp,
and defaults to the current time if time is omitted or
nil) to a string according to format-string. The
conversion uses the time zone rule zone, which defaults to the
current time zone rule. See Time Zone Rules. The argument
format-string may contain ‘%’-sequences which say to
substitute parts of the time. Here is a table of what the
‘%’-sequences mean:
This stands for the abbreviated name of the day of week.
This stands for the full name of the day of week.
This stands for the abbreviated name of the month.
This stands for the full name of the month.
This is a synonym for ‘%x %X’.
This stands for the century, that is, the year divided by 100, truncated toward zero. The default field width is 2.
This stands for the day of month, zero-padded.
This is a synonym for ‘%m/%d/%y’.
This stands for the day of month, blank-padded.
This stands for the ISO 8601 date format, which is like ‘%+4Y-%m-%d’ except that any flags or field width override the ‘+’ and (after subtracting 6) the ‘4’.
This stands for the year without century (00–99) corresponding to the current ISO week number. ISO weeks start on Monday and end on Sunday. If an ISO week begins in one year and ends in another, the rules regarding which year ‘%g’ will produce are complex and will not be described here; however, in general, if most of the week’s days are in the ending year, ‘%g’ will produce that year.
This stands for the year with century corresponding to the current ISO week number.
This is a synonym for ‘%b’.
This stands for the hour (00–23).
This stands for the hour (01–12).
This stands for the day of the year (001–366).
This stands for the hour (0–23), blank padded.
This stands for the hour (1–12), blank padded.
This stands for the month (01–12).
This stands for the minute (00–59).
This stands for a newline.
This stands for the nanoseconds (000000000–999999999). To ask for fewer digits, use ‘%3N’ for milliseconds, ‘%6N’ for microseconds, etc. Any excess digits are discarded, without rounding.
This stands for ‘AM’ or ‘PM’, as appropriate.
This stands for the calendar quarter (1–4).
This is a synonym for ‘%I:%M:%S %p’.
This is a synonym for ‘%H:%M’.
This stands for the integer number of seconds since the epoch.
This stands for the second (00–59, or 00–60 on platforms that support leap seconds).
This stands for a tab character.
This is a synonym for ‘%H:%M:%S’.
This stands for the numeric day of week (1–7). Monday is day 1.
This stands for the week of the year (01–52), assuming that weeks start on Sunday. If January 1 is not a Sunday, the first partial week is week zero.
This stands for the week of the year according to ISO 8601. Note that, unlike ‘%U’ and ‘%W’, the week according to ISO 8601 does not roll over to 1 on January 1, but keeps its last number.
This stands for the numeric day of week (0–6). Sunday is day 0.
This stands for the week of the year (01–52), assuming that weeks start on Monday. If January 1 is not a Monday, the first partial week is week zero.
This has a locale-specific meaning. In the default locale (named ‘C’), it is equivalent to ‘%D’.
This has a locale-specific meaning. In the default locale (named ‘C’), it is equivalent to ‘%T’.
This stands for the year without century (00–99).
This stands for the year with century.
This stands for the time zone abbreviation (e.g., ‘EST’).
This stands for the time zone numerical offset. The ‘z’ can be preceded by one, two, or three colons; if plain ‘%z’ stands for ‘-0500’, then ‘%:z’ stands for ‘-05:00’, ‘%::z’ stands for ‘-05:00:00’, and ‘%:::z’ is like ‘%::z’ except it suppresses trailing instances of ‘:00’ so it stands for ‘-05’ in the same example.
This stands for a single ‘%’.
One or more flag characters can appear immediately after the ‘%’. ‘0’ pads with zeros, ‘+’ pads with zeros and also puts ‘+’ before nonnegative year numbers with more than four digits, ‘_’ pads with blanks, ‘-’ suppresses padding, ‘^’ upper-cases letters, and ‘#’ reverses the case of letters.
You can also specify the field width and type of padding for any of
these ‘%’-sequences. This works as in printf: you write
the field width as digits in a ‘%’-sequence, after any flags.
For example, ‘%S’ specifies the number of seconds since the minute;
‘%03S’ means to pad this with zeros to 3 positions, ‘%_3S’ to
pad with spaces to 3 positions. Plain ‘%3S’ pads with zeros,
because that is how ‘%S’ normally pads to two positions.
The characters ‘E’ and ‘O’ act as modifiers when used after
any flags and field widths in a ‘%’-sequence. ‘E’ specifies
using the current locale’s alternative version of the date and time.
In a Japanese locale, for example, %Ex might yield a date format
based on the Japanese Emperors’ reigns. ‘E’ is allowed in
‘%Ec’, ‘%EC’, ‘%Ex’, ‘%EX’, ‘%Ey’, and
‘%EY’.
‘O’ means to use the current locale’s alternative representation of numbers, instead of the ordinary decimal digits. This is allowed with most letters, all the ones that output numbers.
To help debug programs, unrecognized ‘%’-sequences stand for themselves and are output as-is. Programs should not rely on this behavior, as future versions of Emacs may recognize new ‘%’-sequences as extensions.
This function uses the C library function strftime
(see Formatting Calendar Time in The GNU C Library Reference
Manual) to do most of the work. In order to communicate with that
function, it first converts time and zone to internal form;
the operating system limits the range of time and zone values.
This function also encodes format-string using the coding system
specified by locale-coding-system (see Locales); after
strftime returns the resulting string,
this function decodes the string using that same coding
system.
This function converts its argument seconds into a string of years, days, hours, etc., according to format-string. The argument format-string may contain ‘%’-sequences which control the conversion. Here is a table of what the ‘%’-sequences mean:
The integer number of 365-day years.
The integer number of days.
The integer number of hours.
The integer number of minutes.
The number of seconds. If the optional ‘,’ parameter is used, it’s a floating point number, and the number after the ‘,’ specifies how many decimals to be used. ‘%,2s’ means “use two decimals”.
Non-printing control flag. When it is used, other specifiers must be
given in the order of decreasing size, i.e., years before days, hours
before minutes, etc. Nothing will be produced in the result string to
the left of ‘%z’ until the first non-zero conversion is
encountered. For example, the default format used by
emacs-uptime (see emacs-uptime)
"%Y, %D, %H, %M, %z%S" means that the number of seconds
will always be produced, but years, days, hours, and minutes will only
be shown if they are non-zero.
Non-printing control flag that works along the same lines as ‘%z’, but instead suppresses printing of trailing zero-value time elements.
Produces a literal ‘%’.
Upper-case format sequences produce the units in addition to the numbers, lower-case formats produce only the numbers.
You can also specify the field width by following the ‘%’ with a
number; shorter numbers will be padded with blanks. An optional
period before the width requests zero-padding instead. For example,
"%.3Y" might produce "004 years".
Emacs provides several functions and primitives that return time, both elapsed and processor time, used by the Emacs process.
This function returns a string representing the Emacs
uptime—the elapsed wall-clock time this instance of Emacs is
running. The string is formatted by format-seconds according
to the optional argument format. For the available format
descriptors, see format-seconds. If format
is nil or omitted, it defaults to "%Y, %D, %H, %M,
%z%S".
When called interactively, it prints the uptime in the echo area.
This function returns the processor run time used by Emacs, as a Lisp timestamp (see Time of Day).
Note that the time returned by this function excludes the time Emacs was not using the processor, and if the Emacs process has several threads, the returned value is the sum of the processor times used up by all Emacs threads.
If the system doesn’t provide a way to determine the processor run
time, get-internal-run-time returns the same time as
current-time.
This function returns the duration of the Emacs initialization (see Summary: Sequence of Actions at Startup) in seconds, as a string. When called interactively, it prints the duration in the echo area.
These functions perform calendrical computations using time values
(see Time of Day). As with any time value, a value of
nil for any of their
time-value arguments stands for the current system time, and a finite
number stands for the number of seconds since the epoch.
This returns t if the time value t1 is less than the time value
t2.
This returns t if the two time values t1 and t2 are
equal. The result is nil if either argument is a NaN.
For the purpose of comparison, a nil argument represents the
current time with infinite resolution, so this function returns
nil if one argument is nil and the other is not, and
callers can therefore use nil to represent an unknown time
value that does not equal any timestamp.
This returns the time difference t1 − t2 between
two time values, as a Lisp timestamp. The result is exact and its clock
resolution is no worse than the worse of its two arguments’ resolutions.
If you need the difference in units
of elapsed seconds, you can convert it with time-convert or
float-time. See Time Conversion.
This returns the sum of two time values,
using the same conversion rules as time-subtract.
One argument should represent a time difference rather than a point in time,
as a time value that is often just a single number of elapsed seconds.
Here is how to add a number of seconds to a time value:
(time-add time seconds)
This function returns the number of days between the beginning of year 1 and time-value, assuming the default time zone. The operating system limits the range of time and zone values.
This is not quite the inverse of the time-to-days function, as
it uses the Emacs epoch (instead of the year 1) for historical
reasons. To get the inverse, subtract (time-to-days 0) from
days, in which case days-to-time may return nil if
days is negative.
This returns the day number within the year corresponding to time-value, assuming the default time zone. The operating system limits the range of time and zone values.
This function returns t if year is a leap year.
Return the number of days in month in year. For instance, February 2020 has 29 days.
Return the date of ordinal in year as a decoded time structure. For instance, the 120th day in 2004 is April 29th.
You can set up a timer to call a function at a specified future time or after a certain length of idleness. A timer is a special object that stores the information about the next invocation times and the function to invoke.
This predicate function returns non-nil if object is a
timer.
Emacs cannot run timers at any arbitrary point in a Lisp program; it
can run them only when Emacs could accept output from a subprocess:
namely, while waiting or inside certain primitive functions such as
sit-for or read-event which can wait. Therefore, a
timer’s execution may be delayed if Emacs is busy. However, the time of
execution is very precise if Emacs is idle.
Emacs binds inhibit-quit to t before calling the timer
function, because quitting out of many timer functions can leave
things in an inconsistent state. This is normally unproblematical
because most timer functions don’t do a lot of work. Indeed, for a
timer to call a function that takes substantial time to run is likely
to be annoying. If a timer function needs to allow quitting, it
should use with-local-quit (see 退出). For example, if
a timer function calls accept-process-output to receive output
from an external process, that call should be wrapped inside
with-local-quit, to ensure that C-g works if the external
process hangs.
It is usually a bad idea for timer functions to alter buffer
contents. When they do, they usually should call undo-boundary
both before and after changing the buffer, to separate the timer’s
changes from user commands’ changes and prevent a single undo entry
from growing to be quite large.
Timer functions should also avoid calling functions that cause Emacs
to wait, such as sit-for (see 等待时间流逝或输入). This can lead to
unpredictable effects, since other timers (or even the same timer) can
run while waiting. If a timer function needs to perform an action
after a certain time has elapsed, it can do this by scheduling a new
timer.
If a timer function performs a remote file operation, it can be in
conflict with an already running remote file operation of the same
connection. Such conflicts are detected, and they result in a
remote-file-error error (see Standard Errors). This should
be protected by wrapping the timer function body with
(ignore-error 'remote-file-error ...)
If a timer function calls functions that can change the match data, it should save and restore the match data. See Saving and Restoring the Match Data.
This sets up a timer that calls the function function with
arguments args at time time. If repeat is a number
(integer or floating point), the timer is scheduled to run again every
repeat seconds after time. If repeat is nil,
the timer runs only once.
time may specify an absolute or a relative time.
Absolute times may be specified using a string with a limited variety of formats, and are taken to be times today, even if already in the past. The recognized forms are ‘xxxx’, ‘x:xx’, or ‘xx:xx’ (military time), and ‘xxam’, ‘xxAM’, ‘xxpm’, ‘xxPM’, ‘xx:xxam’, ‘xx:xxAM’, ‘xx:xxpm’, or ‘xx:xxPM’. A period can be used instead of a colon to separate the hour and minute parts.
To specify a relative time as a string, use numbers followed by units. For example:
denotes 1 minute from now.
denotes 65 seconds from now.
denotes exactly 103 months, 123 days, and 10862 seconds from now.
For relative time values, Emacs considers a month to be exactly thirty days, and a year to be exactly 365.25 days.
Not all convenient formats are strings. If time is a number
(integer or floating point), that specifies a relative time measured in
seconds. The result of encode-time can also be used to specify
an absolute value for time.
In most cases, repeat has no effect on when first call
takes place—time alone specifies that. There is one exception:
if time is t, then the timer runs whenever the time is a
multiple of repeat seconds after the epoch. This is useful for
functions like display-time. For instance, the following will
make function run at every “whole” minute (e.g.,
‘11:03:00’, ‘11:04:00’, etc):
(run-at-time t 60 function)
If Emacs didn’t get any CPU time when the timer would have run (for example if the system was busy running another process or if the computer was sleeping or in a suspended state), the timer will run as soon as Emacs resumes and is idle.
The function run-at-time returns a timer value that identifies
the particular scheduled future action. You can use this value to call
cancel-timer (see below).
This is exactly the same as run-at-time (so see that definition
for an explanation of the parameters; secs is passed as
time to that function), but is meant to be used when the delay
is specified in seconds.
A repeating timer nominally ought to run every repeat seconds, but remember that any invocation of a timer can be late. Lateness of one repetition has no effect on the scheduled time of the next repetition. For instance, if Emacs is busy computing for long enough to cover three scheduled repetitions of the timer, and then starts to wait, it will immediately call the timer function three times in immediate succession (presuming no other timers trigger before or between them). If you want a timer to run again no less than n seconds after the last invocation, don’t use the repeat argument. Instead, the timer function should explicitly reschedule the timer.
This variable’s value specifies the maximum number of times to repeat calling a timer function in a row, when many previously scheduled calls were unavoidably delayed.
Execute body, but give up after seconds seconds. If
body finishes before the time is up, with-timeout returns
the value of the last form in body. If, however, the execution of
body is cut short by the timeout, then with-timeout
executes all the timeout-forms and returns the value of the last
of them.
This macro works by setting a timer to run after seconds seconds. If body finishes before that time, it cancels the timer. If the timer actually runs, it terminates execution of body, then executes timeout-forms.
Since timers can run within a Lisp program only when the program calls a
primitive that can wait, with-timeout cannot stop executing
body while it is in the midst of a computation—only when it
calls one of those primitives. So use with-timeout only with a
body that waits for input, not one that does a long computation.
The function y-or-n-p-with-timeout provides a simple way to use
a timer to avoid waiting too long for an answer. See Yes-or-No 查询.
This cancels the requested action for timer, which should be a
timer—usually, one previously returned by run-at-time or
run-with-idle-timer. This cancels the effect of that call to
one of these functions; the arrival of the specified time will not
cause anything special to happen.
The list-timers command lists all the currently active timers.
The command c (timer-list-cancel) will cancel the timer
on the line under point. You can sort the list by column using the
command S (tabulated-list-sort).
Here is how to set up a timer that runs when Emacs is idle for a certain length of time. Aside from how to set them up, idle timers work just like ordinary timers.
Set up a timer which runs the next time Emacs is idle for secs
seconds. The value of secs may be a number or a value of the type
returned by current-idle-time.
If repeat is nil, the timer runs just once, the first time
Emacs remains idle for a long enough time. More often repeat is
non-nil, which means to run the timer each time Emacs
remains idle for secs seconds.
The function run-with-idle-timer returns a timer value which you
can use in calling cancel-timer (see Timers for Delayed Execution).
Emacs becomes idle when it starts waiting for user input
(unless it waits for input with a timeout, see 读取单个事件), and
it remains idle until the user provides some input. If a timer is set
for five seconds of idleness, it runs approximately five seconds after
Emacs first becomes idle. Even if repeat is non-nil,
this timer will not run again as long as Emacs remains idle, because
the duration of idleness will continue to increase and will not go
down to five seconds again.
Emacs can do various things while idle: garbage collect, autosave or handle data from a subprocess. But these interludes during idleness do not interfere with idle timers, because they do not reset the clock of idleness to zero. An idle timer set for 600 seconds will run when ten minutes have elapsed since the last user command was finished, even if subprocess output has been accepted thousands of times within those ten minutes, and even if there have been garbage collections and autosaves.
When the user supplies input, Emacs becomes non-idle while executing the input. Then it becomes idle again, and all the idle timers that are set up to repeat will subsequently run another time, one by one.
Do not write an idle timer function containing a loop which does a
certain amount of processing each time around, and exits when
(input-pending-p) is non-nil. This approach seems very
natural but has two problems:
Similarly, do not write an idle timer function that sets up another idle timer (including the same idle timer) with secs argument less than or equal to the current idleness time. Such a timer will run almost immediately, and continue running again and again, instead of waiting for the next time Emacs becomes idle. The correct approach is to reschedule with an appropriate increment of the current value of the idleness time, as described below.
If Emacs is idle, this function returns the length of time Emacs has
been idle, using the same format as
current-time (see Time of Day).
When Emacs is not idle, current-idle-time returns nil.
This is a convenient way to test whether Emacs is idle.
The main use of current-idle-time is when an idle timer
function wants to “take a break” for a while. It can set up another
idle timer to call the same function again, after a few seconds more
idleness. Here’s an example:
(defvar my-resume-timer nil "Timer for `my-timer-function' to reschedule itself, or nil.") (defun my-timer-function () ;; If the user types a command whilemy-resume-timer;; is active, the next time this function is called from ;; its main idle timer, deactivatemy-resume-timer. (when my-resume-timer (cancel-timer my-resume-timer)) ...do the work for a while... (when taking-a-break (setq my-resume-timer (run-with-idle-timer ;; Compute an idle time break-length ;; more than the current value. (time-add (current-idle-time) break-length) nil 'my-timer-function))))
This section describes functions and variables for recording or manipulating terminal input. See Emacs Display, for related functions.
This function sets the mode for reading keyboard input. If
interrupt is non-nil, then Emacs uses input interrupts.
If it is nil, then it uses CBREAK mode. The default
setting is system-dependent. Some systems always use CBREAK mode
regardless of what is specified.
When Emacs communicates directly with X, it ignores this argument and uses interrupts if that is the way it knows how to communicate.
If flow is non-nil, then Emacs uses XON/XOFF
(C-q, C-s) flow control for output to the terminal. This
has no effect except in CBREAK mode.
The argument meta controls support for input character codes
above 127. If meta is t, Emacs converts characters with
the 8th bit set into Meta characters, before it decodes them as needed
(see Terminal I/O Encoding). If meta is nil,
Emacs disregards the 8th bit; this is necessary when the terminal uses
it as a parity bit. If meta is the symbol encoded, Emacs
first decodes the characters using all the 8 bits of each byte, and
then converts the decoded single-byte characters into Meta characters
if they have their eighth bit set. Finally, if meta is neither
t nor nil nor encoded, Emacs uses all 8 bits of
input unchanged, both before and after decoding them. This is good
for terminals that use 8-bit character sets and don’t encode the Meta
modifier as the eighth bit.
If quit-char is non-nil, it specifies the character to
use for quitting. Normally this character is C-g.
See 退出.
The current-input-mode function returns the input mode settings
Emacs is currently using.
This function returns the current mode for reading keyboard input. It
returns a list, corresponding to the arguments of set-input-mode,
of the form (interrupt flow meta quit) in
which:
is non-nil when Emacs is using interrupt-driven input. If
nil, Emacs is using CBREAK mode.
is non-nil if Emacs uses XON/XOFF (C-q, C-s)
flow control for output to the terminal. This value is meaningful only
when interrupt is nil.
is t if Emacs treats the eighth bit of input characters as
the Meta bit before decoding input; encoded if Emacs treats the
eighth bit of the decoded single-byte characters as the Meta bit;
nil if Emacs clears the eighth bit of every input character;
any other value means Emacs uses all eight bits as the basic character
code.
is the character Emacs currently uses for quitting, usually C-g.
This function returns a vector containing the last 300 input events from the keyboard or mouse. All input events are included, whether or not they were used as parts of key sequences. Thus, you always get the last 300 input events, not counting events generated by keyboard macros. (These are excluded because they are less interesting for debugging; it should be enough to see the events that invoked the macros.)
If include-cmds is non-nil, complete key sequences in the
result vector are interleaved with pseudo-events of the form
(nil . COMMAND), where COMMAND is the binding of
the key sequence (see 命令循环概述).
A call to clear-this-command-keys (see 来自命令循环的信息)
causes this function to return an empty vector immediately afterward.
This function opens a dribble file named filename. When a dribble file is open, each input event from the keyboard or mouse (but not those from keyboard macros) is written in that file. A non-character event is expressed using its printed representation surrounded by ‘<…>’. Be aware that sensitive information (such as passwords) may end up recorded in the dribble file.
You close the dribble file by calling this function with an argument
of nil.
See also the open-termscript function (see Terminal Output).
The terminal output functions send output to a text terminal, or keep
track of output sent to the terminal. The variable baud-rate
tells you what Emacs thinks is the output speed of the terminal.
This variable’s value is the output speed of the terminal, as far as Emacs knows. Setting this variable does not change the speed of actual data transmission, but the value is used for calculations such as padding.
It also affects decisions about whether to scroll part of the screen or repaint on text terminals. See Forcing Redisplay, for the corresponding functionality on graphical terminals.
The value is measured in baud.
If you are running across a network, and different parts of the
network work at different baud rates, the value returned by Emacs may be
different from the value used by your local terminal. Some network
protocols communicate the local terminal speed to the remote machine, so
that Emacs and other programs can get the proper value, but others do
not. If Emacs has the wrong value, it makes decisions that are less
than optimal. To fix the problem, set baud-rate.
This function sends string to terminal without alteration.
Control characters in string have terminal-dependent effects.
(If you need to display non-ASCII text on the terminal, encode it
using one of the functions described in Explicit Encoding and Decoding.)
This function operates only on text terminals. terminal may be
a terminal object, a frame, or nil for the selected frame’s
terminal. In batch mode, string is sent to stdout when
terminal is nil.
One use of this function is to define function keys on terminals that have downloadable function key definitions. For example, this is how (on certain terminals) to define function key 4 to move forward four characters (by transmitting the characters C-u C-f to the computer):
(send-string-to-terminal "\eF4\^U\^F")
⇒ nil
This function is used to open a termscript file that will record
all the characters sent by Emacs to the terminal. It returns
nil. Termscript files are useful for investigating problems
where Emacs garbles the screen, problems that are due to incorrect
Termcap entries or to undesirable settings of terminal options more
often than to actual Emacs bugs. Once you are certain which characters
were actually output, you can determine reliably whether they correspond
to the Termcap specifications in use.
(open-termscript "../junk/termscript")
⇒ nil
You close the termscript file by calling this function with an
argument of nil.
See also open-dribble-file in Recording Input.
To play sound using Emacs, use the function play-sound. Only
certain systems are supported; if you call play-sound on a
system which cannot really do the job, it gives an error.
The sound must be stored as a file in RIFF-WAVE format (‘.wav’) or Sun Audio format (‘.au’).
This function plays a specified sound. The argument, sound, has
the form (sound properties...), where the properties
consist of alternating keywords (particular symbols recognized
specially) and values corresponding to them.
Here is a table of the keywords that are currently meaningful in sound, and their meanings:
:file fileThis specifies the file containing the sound to play.
If the file name is not absolute, it is expanded against
the directory data-directory.
:data dataThis specifies the sound to play without need to refer to a file. The value, data, should be a string containing the same bytes as a sound file. We recommend using a unibyte string.
:volume volumeThis specifies how loud to play the sound. It should be a number in the range of 0 to 1. The default is to use whatever volume has been specified before.
:device deviceThis specifies the system device on which to play the sound, as a string. The default device is system-dependent.
Before actually playing the sound, play-sound
calls the functions in the list play-sound-functions.
Each function is called with one argument, sound.
This function is an alternative interface to playing a sound file specifying an optional volume and device.
A list of functions to be called before playing a sound. Each function is called with one argument, a property list that describes the sound.
To define system-specific X11 keysyms, set the variable
system-key-alist.
This variable’s value should be an alist with one element for each
system-specific keysym. Each element has the form (code
. symbol), where code is the numeric keysym code (not
including the vendor-specific bit,
−2**28),
and symbol is the name for the function key.
For example (168 . mute-acute) defines a system-specific key (used
by HP X servers) whose numeric code is
−2**28
+ 168.
It is not crucial to exclude from the alist the keysyms of other X servers; those do no harm, as long as they don’t conflict with the ones used by the X server actually in use.
The variable is always local to the current terminal, and cannot be buffer-local. See Multiple Terminals.
You can specify which keysyms Emacs should use for the Control, Meta, Alt, Hyper, and Super modifiers by setting these variables:
The name of the keysym that should stand for the Control modifier (respectively, for Alt, Meta, Hyper, and Super). For example, here is how to swap the Meta and Alt modifiers within Emacs:
(setq x-alt-keysym 'meta) (setq x-meta-keysym 'alt)
The command-line option ‘-batch’ causes Emacs to run noninteractively. In this mode, Emacs does not read commands from the terminal, it does not alter the terminal modes, and it does not expect to be outputting to an erasable screen. The idea is that you specify Lisp programs to run; when they are finished, Emacs should exit. The way to specify the programs to run is with ‘-l file’, which loads the library named file, or ‘-f function’, which calls function with no arguments, or ‘--eval=form’.
This variable is non-nil when Emacs is running in batch mode.
If the specified Lisp program signals an unhandled error in batch mode, Emacs exits with a non-zero exit status after invoking the Lisp debugger which shows the Lisp backtrace (see 调用调试器) on the standard error stream:
$ emacs -Q --batch --eval '(error "foo")'; echo $?
Error: error ("foo")
mapbacktrace(#f(compiled-function (evald func args flags) #<bytecode -0x4f85c5
7c45e2f81>))
debug-early-backtrace()
debug-early(error (error "foo"))
signal(error ("foo"))
error("foo")
eval((error "foo") t)
command-line-1(("--eval" "(error \"foo\")"))
command-line()
normal-top-level()
foo 255
Any Lisp program output that would normally go to the echo area,
either using message, or using prin1, etc., with
t as the stream (see 输出流), goes instead to
Emacs’s standard descriptors when in batch mode: message writes
to the standard error descriptor, while prin1 and other print
functions write to the standard output. Similarly, input that would
normally come from the minibuffer is read from the standard input
descriptor. Thus, Emacs behaves much like a noninteractive
application program. (The echo area output that Emacs itself normally
generates, such as command echoing, is suppressed entirely.)
Non-ASCII text written to the standard output or error descriptors is
by default encoded using locale-coding-system (see Locales)
if it is non-nil; this can be overridden by binding
coding-system-for-write to a coding system of you choice
(see Explicit Encoding and Decoding).
In batch mode, Emacs will enlarge the value of the
gc-cons-percentage variable from the default of ‘0.1’ up to
‘1.0’. Batch jobs that are supposed to run for a long time
should adjust the limit back down again, because this means that less
garbage collection will be performed by default (and more memory
consumed).
Emacs supports the X Session Management Protocol, which is used to suspend and restart applications. In the X Window System, a program called the session manager is responsible for keeping track of the applications that are running. When the X server shuts down, the session manager asks applications to save their state, and delays the actual shutdown until they respond. An application can also cancel the shutdown.
When the session manager restarts a suspended session, it directs these applications to individually reload their saved state. It does this by specifying a special command-line argument that says what saved session to restore. For Emacs, this argument is ‘--smid session’.
Emacs supports saving state via a hook called
emacs-save-session-functions. Emacs runs this hook when the
session manager tells it that the window system is shutting down. The
functions are called with no arguments, and with the current buffer
set to a temporary buffer. Each function can use insert to add
Lisp code to this buffer. At the end, Emacs saves the buffer in a
file, called the session file.
Subsequently, when the session manager restarts Emacs, it loads the
session file automatically (see 加载). This is performed by a
function named emacs-session-restore, which is called during
startup. See Summary: Sequence of Actions at Startup.
If a function in emacs-save-session-functions returns
non-nil, Emacs tells the session manager to cancel the
shutdown.
Here is an example that just inserts some text into *scratch* when Emacs is restarted by the session manager.
(add-hook 'emacs-save-session-functions 'save-yourself-test)
(defun save-yourself-test ()
(insert
(format "%S" '(with-current-buffer "*scratch*"
(insert "I am restored"))))
nil)
Emacs is able to send notifications on systems that support the freedesktop.org Desktop Notifications Specification, MS-Windows, Haiku, and Android.
In order to use this functionality on POSIX hosts, Emacs must have
been compiled with D-Bus support, and the notifications library
must be loaded. See D-Bus in D-Bus integration in Emacs.
The following function is supported when D-Bus support is available:
This function sends a notification to the desktop via D-Bus, consisting of the parameters specified by the params arguments. These arguments should consist of alternating keyword and value pairs. The supported keywords and values are as follows:
:bus busThe D-Bus bus. This argument is needed only if a bus other than
:session shall be used.
:title titleThe notification title.
:body textThe notification body text. Depending on the implementation of the notification server, the text could contain HTML markups, like ‘"<b>bold text</b>"’, hyperlinks, or images. Special HTML characters must be encoded, as ‘"Contact <postmaster@localhost>!"’.
:app-name nameThe name of the application sending the notification. The default is
notifications-application-name.
:replaces-id idThe notification id that this notification replaces. id
must be the result of a previous notifications-notify call.
:app-icon icon-fileThe file name of the notification icon. If set to nil, no icon
is displayed. The default is notifications-application-icon.
If the value is a string, the function interprets it as a file name
and converts to absolute by using expand-file-name; if it is a
symbol, the function will use its name (which is useful when using the
Icon Naming Specification 34).
:actions (key title key title ...)A list of actions to be applied. key and title are both strings. The default action (usually invoked by clicking the notification) should have a key named ‘"default"’. The title can be anything, though implementations are free not to display it.
:timeout timeoutThe timeout time in milliseconds since the display of the notification at which the notification should automatically close. If −1, the notification’s expiration time is dependent on the notification server’s settings, and may vary for the type of notification. If 0, the notification never expires. Default value is −1.
:urgency urgencyThe urgency level. It can be low, normal, or critical.
:action-itemsWhen this keyword is given, the title string of the actions is interpreted as icon name.
:category categoryThe type of notification this is, a string. See the Desktop Notifications Specification for a list of standard categories.
:desktop-entry filenameThis specifies the name of the desktop filename representing the calling program, like ‘"emacs"’.
:image-data (width height rowstride has-alpha bits channels data)This is a raw data image format that describes the width, height, rowstride, whether there is an alpha channel, bits per sample, channels and image data, respectively.
:image-path pathThis is represented either as a URI (‘file://’ is the only URI schema supported right now) or a name in a freedesktop.org-compliant icon theme from ‘$XDG_DATA_DIRS/icons’.
:sound-file filenameThe path to a sound file to play when the notification pops up.
:sound-name nameA themable named sound from the freedesktop.org sound naming specification from ‘$XDG_DATA_DIRS/sounds’, to play when the notification pops up. Similar to the icon name, only for sounds. An example would be ‘"message-new-instant"’.
:suppress-soundCauses the server to suppress playing any sounds, if it has that ability.
:residentWhen set the server will not automatically remove the notification
when an action has been invoked. The notification will remain resident
in the server until it is explicitly removed by the user or by the
sender. This hint is likely only useful when the server has the
:persistence capability.
:transientWhen set the server will treat the notification as transient and by-pass the server’s persistence capability, if it should exist.
:x position:y positionSpecifies the X, Y location on the screen that the notification should point to. Both arguments must be used together.
:on-action functionFunction to call when an action is invoked. The notification id and the key of the action are passed as arguments to the function.
:on-close functionFunction to call when the notification has been closed by timeout or by the user. The function receive the notification id and the closing reason as arguments:
expired if the notification has expired
dismissed if the notification was dismissed by the user
close-notification if the notification was closed by a call to
notifications-close-notification
undefined if the notification server hasn’t provided a reason
Which parameters are accepted by the notification server can be
checked via notifications-get-capabilities.
This function returns a notification id, an integer, which can be used
to manipulate the notification item with
notifications-close-notification or the :replaces-id
argument of another notifications-notify call. For example:
(defun my-on-action-function (id key)
(message "Message %d, key \"%s\" pressed" id key))
⇒ my-on-action-function
(defun my-on-close-function (id reason)
(message "Message %d, closed due to \"%s\"" id reason))
⇒ my-on-close-function
(notifications-notify
:title "Title"
:body "This is <b>important</b>."
:actions '("Confirm" "I agree" "Refuse" "I disagree")
:on-action 'my-on-action-function
:on-close 'my-on-close-function)
⇒ 22
A message window opens on the desktop. Press ``I agree''.
⇒ Message 22, key "Confirm" pressed
Message 22, closed due to "dismissed"
This function closes a notification with identifier id.
bus can be a string denoting a D-Bus connection, the default is
:session.
Returns the capabilities of the notification server, a list of
symbols. bus can be a string denoting a D-Bus connection, the
default is :session. The following capabilities can be
expected:
:actionsThe server will provide the specified actions to the user.
:bodySupports body text.
:body-hyperlinksThe server supports hyperlinks in the notifications.
:body-imagesThe server supports images in the notifications.
:body-markupSupports markup in the body text.
:icon-multiThe server will render an animation of all the frames in a given image array.
:icon-staticSupports display of exactly 1 frame of any given image array. This
value is mutually exclusive with :icon-multi.
:persistenceThe server supports persistence of notifications.
:soundThe server supports sounds on notifications.
Further vendor-specific caps start with :x-vendor, like
:x-gnome-foo-cap.
Return information on the notification server, a list of strings.
bus can be a string denoting a D-Bus connection, the default is
:session. The returned list is (name vendor
version spec-version).
The product name of the server.
The vendor name. For example, ‘"KDE"’, ‘"GNOME"’.
The server’s version number.
The specification version the server is compliant with.
If spec_version is nil, the server supports a
specification prior to ‘"1.0"’.
When Emacs runs on MS-Windows as a GUI session, it supports a small subset of the D-Bus notifications functionality via a native primitive:
This function displays an MS-Windows tray notification as specified by params. MS-Windows tray notifications are displayed in a balloon from an icon in the notification area of the taskbar.
Value is the integer unique ID of the notification that can be used to
remove the notification using w32-notification-close, described
below. If the function fails, the return value is nil.
The arguments params are specified as keyword/value pairs. All the
parameters are optional, but if no parameters are specified, the
function will do nothing and return nil.
The following parameters are supported:
:icon iconDisplay icon in the system tray. If icon is a string, it should specify a file name from which to load the icon; the specified file should be a .ico Windows icon file. If icon is not a string, or if this parameter is not specified, the standard Emacs icon will be used.
:tip tipUse tip as the tooltip for the notification. If tip is a string, this is the text of a tooltip that will be shown when the mouse pointer hovers over the tray icon added by the notification. If tip is not a string, or if this parameter is not specified, the default tooltip text is ‘Emacs notification’. The tooltip text can be up to 127 characters long (63 on Windows versions before W2K). Longer strings will be truncated.
:level levelNotification severity level, one of info, warning, or
error. If given, the value determines the icon displayed to the
left of the notification title, but only if the :title parameter
(see below) is also specified and is a string.
:title titleThe title of the notification. If title is a string, it is displayed in a larger font immediately above the body text. The title text can be up to 63 characters long; longer text will be truncated.
:body bodyThe body of the notification. If body is a string, it specifies the text of the notification message. Use embedded newlines to control how the text is broken into lines. The body text can be up to 255 characters long, and will be truncated if it’s longer. Unlike with D-Bus, the body text should be plain text, with no markup.
Note that versions of Windows before W2K support only :icon and
:tip. The other parameters can be passed, but they will be
ignored on those old systems.
There can be at most one active notification at any given time. An
active notification must be removed by calling
w32-notification-close before a new one can be shown.
To remove the notification and its icon from the taskbar, use the following function:
This function removes the tray notification given by its unique id.
When Emacs runs under Haiku as a GUI program, it is also provides a
restricted pastiche of the D-Bus desktop notifications interface
previously addressed. The principle capabilities absent from the
function detailed below are call-back functions such as
:actions, :on-action and :on-close.
This function sends a notification to the desktop notification server,
incorporating a number of parameters that are akin to some of those
accepted by notifications-notify. The parameters are:
:title title:body body:replaces-id replaces-id:urgency urgencyThese have the same meaning as they do when used in calls to
notifications-notify.
:app-icon app-iconThis should be the file name designating an image file to use as the
icon for the notification displayed. If nil, the icon
presented will instead be Emacs’s app icon.
Its return value is a number identifying the notification, which can
be exploited as the :replaces-id parameter to a subsequent call
to this function.
When Emacs is built as an Android application package, displaying
notifications is facilitated by the function
android-notifications-notify. This function does not feature
call-backs, and has several idiosyncrasies, when compared to
notifications-notify.
This function displays a desktop notification. params is a list
of parameters analogous to its namesake in
notifications-notify. The parameters are:
:title title:body body:replaces-id replaces-id:on-action on-action:on-cancel on-close:actions actions:timeout timeout:resident residentThese have the same meaning as they do when used in calls to
notifications-notify, except that no more than three non-default
actions will be displayed.
:urgency urgencyThe set of accepted values for urgency is the same as with
notifications-notify, but the urgency applies to all
notifications displayed with the defined group, except under
Android 7.1 and earlier.
:group groupgroup is a string that designates a category to which the notification sent will belong. This category is reproduced within the system’s notification settings menus, but is ignored under Android 7.1 and earlier.
If group is nil or not present within params, it is replaced by the string ‘"Desktop Notifications"’.
Callers should provide one stable combination of urgency and group for each kind of notification they send, given that the system may elect to disregard urgency if it does not match that of any notification previously delivered to group.
:icon iconThis parameter controls the symbolic icon the notification will be
displayed with. Its value is a string designating an icon within the
android.R.drawable system package. See
R.drawable
| Android Developers for a list of such icons.
If it is not provided within params or icon does not exist, it defaults to ‘"ic_dialog_alert"’.
It returns a number identifying the notification, which may be
supplied as the :replaces-id parameter to a later call to this
function.
If Emacs is not afforded the permission to display notifications (see Android Environment in The GNU Emacs Manual) under Android 13 and later, any notifications sent will be silently disregarded.
Several operating systems support watching of filesystems for changes to files or their attributes. If configured properly, Emacs links a respective library like inotify, kqueue, gfilenotify, or w32notify statically. These libraries enable watching of filesystems on the local machine.
It is also possible to watch filesystems on remote machines, see Remote Files in The GNU Emacs Manual. This does not depend on one of the libraries linked to Emacs.
Since all these libraries emit different events upon notified file
changes, Emacs provides a special library filenotify which
presents a unified interface to applications. Lisp programs that want
to receive file notifications should always use this library in
preference to the native ones. This section documents the
filenotify library functions and variables.
Add a watch for filesystem events pertaining to file. This arranges for filesystem events pertaining to file to be reported to Emacs.
The returned value is a descriptor for the added watch. Its type
depends on the underlying library, and in general cannot be assumed to
be an integer as in the example below. It should be used for
comparison by equal only.
If the file cannot be watched for some reason, this function
signals a file-notify-error error.
Sometimes, mounted filesystems cannot be watched for file changes.
This is not detected by this function, and so a non-nil return
value does not guarantee that changes on file will be actually
notified.
If file is a symlink, it doesn’t follow that link. Just file itself will be watched.
flags is a list of conditions to set what will be watched for. It can include the following symbols:
changewatch for changes in file’s contents
attribute-changewatch for changes in file attributes, like permissions or modification time
If file is a directory, change watches for file creation
and deletion in that directory. Some of the native file notification
libraries also report file changes in that case. This does not work
recursively.
When any event happens, Emacs will call the callback function passing it a single argument event, which is of the form
(descriptor action file [file1])
descriptor is the same object as the one returned by this function. action is the description of the event. It could be any one of the following symbols:
createdfile was created
deletedfile was deleted
changedfile’s contents has changed; with w32notify library, reports attribute changes as well
renamedfile has been renamed to file1
attribute-changeda file attribute was changed
stoppedwatching file has stopped
Note that the w32notify library does not report
attribute-changed events. When some file’s attribute, like
permissions or modification time, has changed, this library reports a
changed event. Likewise, the kqueue library does not
reliably report file attribute changes when watching a directory.
The stopped event means that watching the file has been
discontinued. This could be because file-notify-rm-watch was
called (see below), or because the file being watched was deleted, or
because the filesystem of the file being watched was unmounted, or due
to another error reported from the underlying library which makes
further watching impossible.
file and file1 are the name of the file(s) whose event is being reported. For example:
(require 'filenotify)
⇒ filenotify
(defun my-notify-callback (event)
(message "Event %S" event))
⇒ my-notify-callback
(file-notify-add-watch
"/tmp" '(change attribute-change) 'my-notify-callback)
⇒ 35025468
(write-region "foo" nil "/tmp/foo")
⇒ Event (35025468 created "/tmp/.#foo")
Event (35025468 created "/tmp/foo")
Event (35025468 changed "/tmp/foo")
Event (35025468 deleted "/tmp/.#foo")
(write-region "bla" nil "/tmp/foo")
⇒ Event (35025468 created "/tmp/.#foo")
Event (35025468 changed "/tmp/foo")
Event (35025468 deleted "/tmp/.#foo")
(set-file-modes "/tmp/foo" (default-file-modes) 'nofollow)
⇒ Event (35025468 attribute-changed "/tmp/foo")
Whether the action renamed is returned depends on the used
watch library. Otherwise, the actions deleted and
created could be returned in a random order.
(rename-file "/tmp/foo" "/tmp/bla")
⇒ Event (35025468 renamed "/tmp/foo" "/tmp/bla")
(delete-file "/tmp/bla")
⇒ Event (35025468 deleted "/tmp/bla")
Removes an existing file watch specified by its descriptor.
descriptor should be an object returned by
file-notify-add-watch.
Removes all existing file notification watches from Emacs.
Use this command with caution, because it could have unexpected side effects on packages relying on file watches. It is intended mainly for debugging purposes, or when Emacs has been stalled.
Checks a watch specified by its descriptor for validity.
descriptor should be an object returned by
file-notify-add-watch.
A watch can become invalid if the file or directory it watches is
deleted, or if the watcher thread exits abnormally for any other
reason. Removing the watch by calling file-notify-rm-watch
also makes it invalid.
(make-directory "/tmp/foo")
⇒ Event (35025468 created "/tmp/foo")
(setq desc
(file-notify-add-watch
"/tmp/foo" '(change) 'my-notify-callback))
⇒ 11359632
(file-notify-valid-p desc)
⇒ t
(write-region "bla" nil "/tmp/foo/bla")
⇒ Event (11359632 created "/tmp/foo/.#bla")
Event (11359632 created "/tmp/foo/bla")
Event (11359632 changed "/tmp/foo/bla")
Event (11359632 deleted "/tmp/foo/.#bla")
;; Deleting a file in the directory doesn't invalidate the watch.
(delete-file "/tmp/foo/bla")
⇒ Event (11359632 deleted "/tmp/foo/bla")
(write-region "bla" nil "/tmp/foo/bla")
⇒ Event (11359632 created "/tmp/foo/.#bla")
Event (11359632 created "/tmp/foo/bla")
Event (11359632 changed "/tmp/foo/bla")
Event (11359632 deleted "/tmp/foo/.#bla")
;; Deleting the directory invalidates the watch.
;; Events arrive for different watch descriptors.
(delete-directory "/tmp/foo" 'recursive)
⇒ Event (35025468 deleted "/tmp/foo")
Event (11359632 deleted "/tmp/foo/bla")
Event (11359632 deleted "/tmp/foo")
Event (11359632 stopped "/tmp/foo")
(file-notify-valid-p desc)
⇒ nil
A dynamically loaded library is a library that is loaded on demand, when its facilities are first needed. Emacs supports such on-demand loading of support libraries for some of its features.
This is an alist of dynamic libraries and external library files implementing them.
Each element is a list of the form
(library files…), where the car is
a symbol representing a supported external library, and the rest are
strings giving alternate filenames for that library.
Emacs tries to load the library from the files in the order they appear in the list; if none is found, the Emacs session won’t have access to that library, and the features it provides will be unavailable.
Image support on some platforms uses this facility. Here’s an example of setting this variable for supporting images on MS-Windows:
(setq dynamic-library-alist
'((xpm "libxpm.dll" "xpm4.dll" "libXpm-nox4.dll")
(png "libpng12d.dll" "libpng12.dll" "libpng.dll"
"libpng13d.dll" "libpng13.dll")
(jpeg "jpeg62.dll" "libjpeg.dll" "jpeg-62.dll"
"jpeg.dll")
(tiff "libtiff3.dll" "libtiff.dll")
(gif "giflib4.dll" "libungif4.dll" "libungif.dll")
(svg "librsvg-2-2.dll")
(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll")
(glib "libglib-2.0-0.dll")
(gobject "libgobject-2.0-0.dll")))
Note that image types pbm and xbm do not need entries in
this variable because they do not depend on external libraries and are
always available in Emacs.
Also note that this variable is not meant to be a generic facility for accessing external libraries; only those already known by Emacs can be loaded through it.
This variable is ignored if the given library is statically linked into Emacs.
Like any application, Emacs can be run in a secure environment, where the operating system enforces rules about access and the like. With some care, Emacs-based applications can also be part of a security perimeter that checks such rules. Although the default settings for Emacs work well for a typical software development environment, they may require adjustment in environments containing untrusted users that may include attackers. Here is a compendium of security issues that may be helpful if you are developing such applications. It is by no means complete; it is intended to give you an idea of the security issues involved, rather than to be a security checklist.
A file that Emacs visits can contain variable settings that affect
the buffer visiting that file; See 文件局部变量.
Similarly, a directory can specify local variable values common to all
files in that directory; see 目录局部变量. Although
Emacs takes some effort to protect against misuse of these variables,
a security hole can be created merely by a package setting
safe-local-variable too optimistically, a problem that is all
too common. To disable this feature for both files and directories,
set enable-local-variables to nil.
Although Emacs normally respects access permissions of the underlying operating system, in some cases it handles accesses specially. For example, file names can have handlers that treat the files specially, with their own access checking. See 实现“魔法”文件名机制. Also, a buffer can be read-only even if the corresponding file is writable, and vice versa, which can result in messages such as ‘File passwd is write-protected; try to save anyway? (yes or no)’. See Read-Only Buffers.
Emacs has several functions that deal with passwords, e.g.,
read-passwd. See 读取密码.
Although these functions do not attempt to
broadcast passwords to the world, their implementations are not proof
against determined attackers with access to Emacs internals. For
example, even if Elisp code uses clear-string to scrub a password from
its memory after using it, remnants of the password may still reside
in the garbage-collected free list. See 修改字符串.
Emacs can send commands to many other applications, and applications
should take care that strings sent as operands of these commands are
not misinterpreted as directives. For example, when using a shell
command to rename a file a to b, do not simply use the
string mv a b, because either file name might start
with ‘-’, or might contain shell metacharacters like ‘;’.
Although functions like shell-quote-argument can help avoid
this sort of problem, they are not panaceas; for example, on a POSIX
platform shell-quote-argument quotes shell metacharacters but
not leading ‘-’. On MS-Windows, quoting for ‘%’ assumes
none of the environment variables have ‘^’ in their name.
See Shell Arguments. Typically it is safer
to use call-process than a subshell. See Creating a Synchronous Process. And it is safer yet to use builtin Emacs functions; for
example, use (rename-file "a" "b" t) instead of
invoking mv. See 修改文件名与属性.
Emacs attempts to infer the coding systems of the files and network connections it accesses. See Coding Systems. If Emacs infers incorrectly, or if the other parties to the network connection disagree with Emacs’s inferences, the resulting system could be unreliable. Also, even when it infers correctly, Emacs often can use bytes that other programs cannot. For example, although to Emacs the null byte is just a character like any other, many other applications treat it as a string terminator and mishandle strings or files containing null bytes.
POSIX specifies several environment variables that can affect how
Emacs behaves. Any environment variable whose name consists entirely
of uppercase ASCII letters, digits, and the underscore may affect the
internal behavior of Emacs. Emacs uses several such variables, e.g.,
EMACSLOADPATH. See 库搜索. On some platforms some
environment variables (e.g., PATH, POSIXLY_CORRECT,
SHELL, TMPDIR) need to have properly-configured values in
order to get standard behavior for any utility Emacs might invoke.
Even seemingly-benign variables like TZ may have security
implications. See Operating System Environment.
Emacs has customization and other variables with similar
considerations. For example, if the variable shell-file-name
specifies a shell with nonstandard behavior, an Emacs-based
application may misbehave.
When Emacs is installed, if the installation directory hierarchy can be modified by untrusted users, the application cannot be trusted. This applies also to the directory hierarchies of the programs that Emacs uses, and of the files that Emacs reads and writes.
Emacs often accesses the network, and you may want to configure it to
avoid network accesses that it would normally do. For example, unless
you set tramp-mode to nil, file names using a certain
syntax are interpreted as being network files, and are retrieved
across the network. See The Tramp Manual in The Tramp
Manual.
Emacs applications have the same sort of race-condition issues that
other applications do. For example, even when
(file-readable-p "foo.txt") returns t, it could be that
foo.txt is unreadable because some other program changed the
file’s permissions between the call to file-readable-p and now.
See 测试文件可访问性.
When Emacs exhausts memory or other operating system resources, its behavior can be less reliable, in that computations that ordinarily run to completion may abort back to the top level. This may cause Emacs to neglect operations that it normally would have done.
Emacs provides a standard way to distribute Emacs Lisp code to users. A package is a collection of one or more files, formatted and bundled in such a way that users can easily download, install, uninstall, and upgrade it.
The following sections describe how to create a package, and how to put it in a package archive for others to download. See Packages in The GNU Emacs Manual, for a description of user-level features of the packaging system.
These sections are mostly directed towards package archive maintainers—much of this information is not relevant for package authors (i.e., people who write code that will be distributed via these archives).
A package is either a simple package or a multi-file package. A simple package is stored in a package archive as a single Emacs Lisp file, while a multi-file package is stored as a tar file (containing multiple Lisp files, and possibly non-Lisp files such as a manual).
In ordinary usage, the difference between simple packages and multi-file packages is relatively unimportant; the Package Menu interface makes no distinction between them. However, the procedure for creating them differs, as explained in the following sections.
Each package (whether simple or multi-file) has certain attributes:
A short word (e.g., ‘auctex’). This is usually also the symbol prefix used in the program (see Emacs Lisp Coding Conventions).
A version number, in a form that the function version-to-list
understands (e.g., ‘11.86’). Each release of a package should be
accompanied by an increase in the version number so that it will be
recognized as an upgrade by users querying the package archive.
This is shown when the package is listed in the Package Menu. It should occupy a single line, ideally in 36 characters or less.
This is shown in the buffer created by C-h P
(describe-package), following the package’s brief description
and installation status. It normally spans multiple lines, and should
fully describe the package’s capabilities and how to begin using it
once it is installed.
A list of other packages (possibly including minimal acceptable version numbers) on which this package depends. The list may be empty, meaning this package has no dependencies. Otherwise, installing this package also automatically installs its dependencies, recursively; if any dependency cannot be found, the package cannot be installed.
Installing a package, either via the command package-install-file,
or via the Package Menu, creates a subdirectory of
package-user-dir named name-version, where
name is the package’s name and version its version
(e.g., ~/.emacs.d/elpa/auctex-11.86/). We call this the
package’s content directory. It is where Emacs puts the
package’s contents (the single Lisp file for a simple package, or the
files extracted from a multi-file package).
Emacs then searches every Lisp file in the content directory for
autoload magic comments (see 自动加载). These autoload
definitions are saved to a file named name-autoloads.el
in the content directory. They are typically used to autoload the
principal user commands defined in the package, but they can also
perform other tasks, such as adding an element to
auto-mode-alist (see Emacs 如何选择主模式). Note that a package
typically does not autoload every function and variable defined
within it—only the handful of commands typically called to begin
using the package. Emacs then byte-compiles every Lisp file in the
package.
After installation, the installed package is loaded: Emacs
adds the package’s content directory to load-path, and
evaluates the autoload definitions in name-autoloads.el.
Whenever Emacs starts up, it automatically calls the function
package-activate-all to make installed packages available to the
current session. This is done after loading the early init file, but
before loading the regular init file (see Summary: Sequence of Actions at Startup).
Packages are not automatically made available if the user option
package-enable-at-startup is set to nil in the early
init file.
This function makes the packages available to the current session.
The user option package-load-list specifies which packages to
make available; by default, all installed packages are made available.
See Package Installation in The GNU Emacs Manual.
In most cases, you should not need to call package-activate-all,
as this is done automatically during startup. Simply make sure to put
any code that should run before package-activate-all in the early
init file, and any code that should run after it in the primary init
file (see Init File in The GNU Emacs Manual).
This function initializes Emacs’s internal record of which packages are
installed, and then calls package-activate-all.
The optional argument no-activate, if non-nil, causes
Emacs to update its record of installed packages without actually
making them available.
A simple package consists of a single Emacs Lisp source file. The file must conform to the Emacs Lisp library header conventions (see Conventional Headers for Emacs Libraries). The package’s attributes are taken from the various headers, as illustrated by the following example:
;;; superfrobnicator.el --- Frobnicate and bifurcate flanges -*- lexical-binding:t -*- ;; Copyright (C) 2022, 2025 Free Software Foundation, Inc.
;; Author: J. R. Hacker <[email protected]> ;; Version: 1.3 ;; Package-Requires: ((flange "1.0")) ;; Keywords: multimedia, hypermedia ;; URL: https://example.com/jrhacker/superfrobnicate ... ;;; Commentary: ;; This package provides a minor mode to frobnicate and/or ;; bifurcate any flanges you desire. To activate it, just type ... ;;;###autoload (define-minor-mode superfrobnicator-mode ...
The name of the package is the same as the base name of the file, as written on the first line. Here, it is ‘superfrobnicator’.
The brief description is also taken from the first line. Here, it is ‘Frobnicate and bifurcate flanges’.
The version number comes from the ‘Package-Version’ header, if it exists, or from the ‘Version’ header otherwise. One or the other must be present. Here, the version number is 1.3.
If the file has a ‘;;; Commentary:’ section, this section is used as the long description. (When displaying the description, Emacs omits the ‘;;; Commentary:’ line, as well as the leading comment characters in the commentary itself.)
If the file has a ‘Package-Requires’ header, that is used as the package dependencies. In the above example, the package depends on the ‘flange’ package, version 1.0 or higher. See Conventional Headers for Emacs Libraries, for a description of the ‘Package-Requires’ header. To depend on a specific version of Emacs, specify ‘emacs’ as the package name. If the header is omitted, the package has no dependencies.
The ‘Keywords’ and ‘URL’ headers are optional, but recommended.
The command describe-package uses these to add links to its
output. The ‘Keywords’ header should contain at least one
standard keyword from the finder-known-keywords list.
The file ought to also contain one or more autoload magic comments,
as explained in Packaging Basics. In the above example, a magic
comment autoloads superfrobnicator-mode.
See Creating and Maintaining Package Archives, for an explanation of how to add a single-file package to a package archive.
A multi-file package is less convenient to create than a single-file package, but it offers more features: it can include multiple Emacs Lisp files, an Info manual, and other file types (such as images).
Prior to installation, a multi-file package is stored in a package archive as a tar file. The tar file must be named name-version.tar, where name is the package name and version is the version number. Its contents, once extracted, must all appear in a directory named name-version, the content directory (see Packaging Basics). Files may also extract into subdirectories of the content directory.
One of the files in the content directory must be named
name-pkg.el. It must contain a single Lisp form,
consisting of a call to the function define-package, described
below. This defines the package’s attributes: version, brief
description, and requirements.
For example, if we distribute version 1.3 of the superfrobnicator as a multi-file package, the tar file would be superfrobnicator-1.3.tar. Its contents would extract into the directory superfrobnicator-1.3, and one of these would be the file superfrobnicator-pkg.el.
This function defines a package. name is the package name, a
string. version is the version, as a string of a form that can
be understood by the function version-to-list. docstring
is the brief description.
requirements is a list of required packages and their versions.
Each element in this list should have the form (dep-name
dep-version), where dep-name is a symbol whose name is the
dependency’s package name, and dep-version is the dependency’s
version (a string). The special value ‘emacs’ means that the
package depends on the given version of Emacs.
If the content directory contains a file named README, this file is used as the long description (overriding any ‘;;; Commentary:’ section).
If the content directory contains a file named dir, this is
assumed to be an Info directory file made with install-info.
See Invoking
install-info in Texinfo. The relevant Info files should also
be present in the content directory. In this case, Emacs will
automatically add the content directory to Info-directory-list
when the package is activated.
Do not include any .elc files in the package. Those are created when the package is installed. Note that there is no way to control the order in which files are byte-compiled.
Do not include any file named name-autoloads.el. This file is reserved for the package’s autoload definitions (see Packaging Basics). It is created automatically when the package is installed, by searching all the Lisp files in the package for autoload magic comments.
If the multi-file package contains auxiliary data files (such as
images), the package’s Lisp code can refer to these files via the
variable load-file-name (see 加载). Here is an example:
(defconst superfrobnicator-base (file-name-directory load-file-name)) (defun superfrobnicator-fetch-image (file) (expand-file-name file superfrobnicator-base))
If your package contains files that you don’t wish to distribute to
users (e.g. regression tests), you can add them to an
.elpaignore file. In this file, each line lists a file or a
wildcard matching files; those files should be ignored when producing
your package’s tarball on ELPA (see Creating and Maintaining Package Archives). (ELPA
will pass this file to the tar command via the -X
command-line option, when it prepares the package for download.)
Via the Package Menu, users may download packages from package
archives. Such archives are specified by the variable
package-archives, whose default value lists the archives
hosted on GNU ELPA and
NonGNU ELPA. This section describes
how to set up and maintain a package archive.
A package archive is simply a directory in which the package files, and associated files, are stored. If you want the archive to be reachable via HTTP, this directory must be accessible to a web server; See Interfacing to an archive web server.
After you create an archive, remember that it is not accessible in the
Package Menu interface unless it is in package-archives.
Maintaining a public package archive entails a degree of responsibility. When Emacs users install packages from your archive, those packages can cause Emacs to run arbitrary code with the permissions of the installing user. (This is true for Emacs code in general, not just for packages.) So you should ensure that your archive is well-maintained and keep the hosting system secure.
One way to increase the security of your packages is to sign them using a cryptographic key. If you have generated a private/public gpg key pair, you can use gpg to sign the package like this:
gpg -ba -o file.sig file
For a single-file package, file is the package Lisp file; for a multi-file package, it is the package tar file. You can also sign the archive’s contents file in the same way. Make the .sig files available in the same location as the packages. You should also make your public key available for people to download; e.g., by uploading it to a key server such as https://pgp.mit.edu/. When people install packages from your archive, they can use your public key to verify the signatures.
A full explanation of these matters is outside the scope of this manual. For more information on cryptographic keys and signing, see GnuPG in The GNU Privacy Guard Manual. Emacs comes with an interface to GNU Privacy Guard, see EasyPG in Emacs EasyPG Assistant Manual.
A web server providing access to a package archive must support the following queries:
Return a lisp form describing the archive contents. The form is a list of ’package-desc’ structures (see package.el), except the first element of the list is the archive version.
Return the long description of the package.
Return the signature for the file.
Return the file. This will be the tarball for a multi-file package, or the single file for a simple package.
Packages that wish to support older releases of Emacs, without giving up on newer functionality from recent Emacs releases, one can make use of the Compat package on GNU ELPA. By depending on the package, Emacs can provide compatibility definitions for missing functionality.
The versioning of Compat follows that of Emacs, so next to the oldest
version that a package relies on (via the emacs-package), one
can also indicate what the newest version of Emacs is, that a package
wishes to use definitions from:
;; Package-Requires: ((emacs "27.2") (compat "29.1"))
Note that Compat provides replacement functions with extended
functionality for functions that are already defined (sort,
assoc, …). These functions may have changed their
calling convention (additional optional arguments) or may have changed
their behavior. These functions must be looked up explicitly with
compat-function or called explicitly with compat-call.
We call them Extended Definitions. In contrast, newly Added
Definitions can be called as usual.
This macro calls the compatibility function fun with args.
Many functions provided by Compat can be called directly without this
macro. However in the case where Compat provides an alternative
version of an existing function, the function call has to go through
compat-call.
This macro returns the compatibility function symbol for fun.
See compat-call for a more convenient macro to directly call
compatibility functions.
For further details on how to make use of the package, see Usage in "Compat" Manual. In case you don’t have the manual installed, you can also read the Online Compat manual.
For those users who live backwards in time, here is information about downgrading to Emacs version 29.4. We hope you will enjoy the greater simplicity that results from the absence of many Emacs 30.2 features.
wheel-up/down and sometimes
mouse-4/5/6/7. Lisp programs which use these should once again
be aware of the conventions in effect and behave accordingly.
describe-function no longer distracts you by showing
unnecessary details like the type of the function’s object. Emacs
hackers always know whether a function is a primitive, a native-compiled
Lisp function, or any other kind. Stating the obvious simply wastes the
precious screen estate; as you move into the past, and the typical
dimensions of the screen become smaller, that waste is less and less
justified. So we made the waste smaller.
minibuffer-regexp-mode was removed. Regular expressions are
just strings, so no fancy mode should be needed for editing them.
\x without any following hex digits
as character code zero (NUL), as it always was in Emacs. The
savings in typing due to this alone are enough to justify this
simplification.
value< function and
keyword arguments for sort, were deleted as too complex. The
basic sort function should all that’s needed in the years to go.
provided-mode-derived-p, derived-mode-add-parents, and
others. We decided that untangling the mode inheritance relationships
by hand facilitates more clear code and makes the intent evident.
declare forms for functions, such as
ftype. Emacs Lisp is not a string-typed language, which makes
these declarations anathema. The types closure and
interpreted-function are gone for the same reason: no need to
distinguish types of Lisp functions.
lexical-binding cookies, empty bodies of special forms and
macros, comparison with literals, condition-case without
handlers, mutation of constants, and some others. As time moves into
the past, the typical Emacs hacker knows best what’s correct code and
what isn’t, and thus these warnings become useless annoyances. Good
riddance!
obarray type is gone. Obarrays are back to their original
representation as vectors. Each removed Lisp data type makes Emacs
simpler and easier to use, so this is a welcome deletion.
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/licenses/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
with the Invariant Sections being list their titles, with
the Front-Cover Texts being list, and with the Back-Cover Texts
being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
Copyright © 2007 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program—to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers’ and authors’ protection, the GPL clearly explains that there is no warranty for this free software. For both users’ and authors’ sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users’ freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work’s System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work’s users, your or third parties’ legal rights to forbid circumvention of technological measures.
You may convey verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation’s users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party’s predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor’s “contributor version”.
A contributor’s “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor’s essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient’s use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
one line to give the program's name and a brief idea of what it does. Copyright (C) year name of author This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
program Copyright (C) year name of author This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. This is free software, and you are welcome to redistribute it under certain conditions; type ‘show c’ for details.
The hypothetical commands ‘show w’ and ‘show c’ should show the appropriate parts of the General Public License. Of course, your program’s commands might be different; for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see https://www.gnu.org/licenses/.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read https://www.gnu.org/licenses/why-not-lgpl.html.
This chapter describes no additional features of Emacs Lisp. Instead it gives advice on making effective use of the features described in the previous chapters, and describes conventions Emacs Lisp programmers should follow.
You can automatically check some of the conventions described below
by running the command M-x checkdoc RET when visiting a
Lisp file. It cannot check all of the conventions, and not all the
warnings it gives necessarily correspond to problems, but it is worth
examining them all. Alternatively, use the command M-x
checkdoc-current-buffer RET to check the conventions in the
current buffer, or checkdoc-file when you want to check a file
in batch mode, e.g., with a command run by M-x compile RET.
Here are conventions that you should follow when writing Emacs Lisp code intended for widespread use:
This convention is mandatory for any file that includes custom definitions. If fixing such a file to follow this convention requires an incompatible change, go ahead and make the incompatible change; don’t postpone it.
Occasionally, for a command name intended for users to use, it is more convenient if some words come before the package’s name prefix. For example, it is our convention to have commands that list objects named as ‘list-something’, e.g., a package called ‘frob’ could have a command ‘list-frobs’, when its other global symbols begin with ‘frob-’. Also, constructs that define functions, variables, etc., may work better if they start with ‘define-’, so it’s okay to put the name prefix later on in the name. Outside of these well-established cases, however, err on the side of prepending your name prefix.
If you write a function that you think ought to be added to Emacs under
a certain name, such as twiddle-files, don’t call it by that name
in your program. Call it mylib-twiddle-files in your program,
and send mail to ‘[email protected]’ suggesting we add
it to Emacs. If and when we do, we can change the name easily enough.
If one prefix is insufficient, your package can use two or three alternative common prefixes, so long as they make sense.
lexical-binding in new code, and
converting existing Emacs Lisp code to enable lexical-binding
if it doesn’t already. See 选择 Lisp 方言.
provide at the end of each separate Lisp file.
See 功能.
require to make sure they are loaded.
See 功能.
(eval-when-compile (require 'bar))
This tells Emacs to load bar just before byte-compiling
foo, so that the macro definition is available during
compilation. Using eval-when-compile avoids loading bar
when the compiled version of foo is used. It should be
called before the first use of the macro in the file. See 宏与字节编译.
require that library at the top-level and be done
with it. But if your file contains several independent features, and
only one or two require the extra library, then consider putting
require statements inside the relevant functions rather than at
the top-level. Or use autoload statements to load the extra
library when needed. This way people who don’t use those aspects of
your file do not need to load the extra library.
cl-lib library
rather than the old cl library. The latter library is
deprecated and will be removed in a future version of Emacs.
framep and frame-live-p. We recommend to
avoid using this -p suffix in boolean variable names, unless
the variable is bound to a predicate function; instead, use a
-flag suffix or names like is-foo.
unload-feature will undo the changes usually done by
loading a feature (like adding functions to hooks). However, if
loading feature does something unusual and more complex, you can
define a function named feature-unload-function, and make
it undo any such special changes. unload-feature will then
automatically run this function if it exists. See 卸载.
(defalias 'gnus-point-at-bol
(if (fboundp 'point-at-bol)
'point-at-bol
'line-beginning-position))
eval-after-load and with-eval-after-load in
libraries and packages (see 加载相关钩子). This feature is
meant for personal customizations; using it in a Lisp program is
unclean, because it modifies the behavior of another Lisp file in a
way that’s not visible in that file. This is an obstacle for
debugging, much like advising a function in the other package.
path in its name, preferring file,
file-name, or directory instead, since Emacs follows the
GNU convention to use the term path only for search paths,
which are lists of directory names.
follow-link
condition, so that the link obeys mouse-1-click-follows-link.
See Defining Clickable Text. See Buttons, for an easy method of
implementing such clickable links.
Changing all the Emacs major modes to respect this convention was a lot of work; abandoning this convention would make that work go to waste, and inconvenience users. Please comply with it.
The reason for this rule is that a non-prefix binding for ESC in any context prevents recognition of escape sequences as function keys in that context.
For a state that accepts ordinary Emacs commands, or more generally any kind of state in which ESC followed by a function key or arrow key is potentially meaningful, then you must not define ESC ESC, since that would preclude recognizing an escape sequence after ESC. In these states, you should define ESC ESC ESC as the way to escape. Otherwise, define ESC ESC instead.
Following these conventions will make your program fit better into Emacs when it runs.
next-line or previous-line in programs; nearly
always, forward-line is more convenient as well as more
predictable and robust. See Motion by Text Lines.
In particular, don’t use any of these functions:
beginning-of-buffer, end-of-buffer
replace-string, replace-regexp
insert-file, insert-buffer
If you just want to move point, or replace a certain string, or insert a file or buffer’s contents, without any of the other features intended for interactive users, you can replace these functions with one or two lines of simple Lisp code.
Vectors are advantageous for tables that are substantial in size and are accessed in random order (not searched front to back), provided there is no need to insert or delete elements (only lists allow that).
message function, not princ. See The Echo Area.
error
(or signal). The function error does not return.
See 如何发出错误信号.
Don’t use message, throw, sleep-for, or
beep to report errors.
It is occasionally useful to tell the user where an error originated,
even if debug-on-error is nil. In such cases, a
lower-case Lisp symbol can be prepended to the error message. For
example, the error message “Invalid input” could be extended to say
“some-function: Invalid input”.
yes-or-no-p or
y-or-n-p should start with a capital letter and end with
‘?’.
Enter the answer (default 42):
interactive, if you use a Lisp expression to produce a list
of arguments, don’t try to provide the correct default values for
region or position arguments. Instead, provide nil for those
arguments if they were not specified, and have the function body
compute the default value when the argument is nil. For
instance, write this:
(defun foo (pos) (interactive (list (if specified specified-pos))) (unless pos (setq pos default-pos)) ...)
rather than this:
(defun foo (pos)
(interactive
(list (if specified specified-pos
default-pos)))
...)
This is so that repetition of the command will recompute these defaults based on the current circumstances.
You do not need to take such precautions when you use interactive specs ‘d’, ‘m’ and ‘r’, because they make special arrangements to recompute the argument values on repetition of the command.
Here are ways of improving the execution speed of byte-compiled Lisp programs.
memq, member,
assq, or assoc is even faster than explicit iteration. It
can be worth rearranging a data structure so that one of these primitive
search functions can be used.
byte-compile
property. If the property is non-nil, then the function is
handled specially.
For example, the following input will show you that aref is
compiled specially (see 操作数组的函数):
(get 'aref 'byte-compile)
⇒ byte-compile-two-args
Note that in this case (and many others), you must first load the
bytecomp library, which defines the byte-compile property.
defvar definitions for these variables, like this:
(defvar foo)
Such a definition has no effect except to tell the compiler
not to warn about uses of the variable foo in this file.
declare-function
statement (see 告知编译器某个函数已被定义).
require (see require) for
that package to avoid compilation warnings for them, like this:
(require 'foo)
If you need only macros from some file, you can require it only at compile time (see 编译时求值). For instance,
(eval-when-compile (require 'foo))
with-no-warnings. See 编译器错误.
Here are some tips and conventions for the writing of documentation strings. You can check many of these conventions by running the command M-x checkdoc-minor-mode.
apropos.
You can fill the text if that looks good. Emacs Lisp mode fills
documentation strings to the width specified by
emacs-lisp-docstring-fill-column. However, you can sometimes
make a documentation string much more readable by adjusting its line
breaks with care. Use blank lines between sections if the
documentation string is long.
For a function, the first line should briefly answer the question, “What does this function do?” For a variable, the first line should briefly answer the question, “What does this value mean?” Prefer to answer these questions in a way that will make sense to users and callers of the function or the variable. In particular, do not tell what the function does by enumerating the actions of its code; instead, describe the role of these actions and the function’s contract.
Don’t limit the documentation string to one line; use as many lines as you need to explain the details of how to use the function or variable. Please use complete sentences for the rest of the text too.
eval refers to its first argument as ‘FORM’, because the
actual argument name is form:
Evaluate FORM and return its value.
Also write metasyntactic variables in capital letters, such as when you show the decomposition of a list or vector into subunits, some of which may vary. ‘KEY’ and ‘VALUE’ in the following example illustrate this practice:
The argument TABLE should be an alist whose elements have the form (KEY . VALUE). Here, KEY is ...
foo, write “foo”, not
“Foo” (which is a different symbol).
This might appear to contradict the policy of writing function argument values, but there is no real contradiction; the argument value is not the same thing as the symbol that the function uses to hold the value.
If this puts a lower-case letter at the beginning of a sentence and that annoys you, rewrite the sentence so that the symbol is not at the start of it.
t and nil without surrounding
punctuation. For example:
CODE can be `lambda', nil, or t.
Note that when Emacs displays these doc strings, Emacs will usually display ‘`’ (grave accent) as ‘‘’ (left single quotation mark) and ‘'’ (apostrophe) as ‘’’ (right single quotation mark), if the display supports displaying these characters. See 文档中的按键绑定替换. (Some previous versions of this section recommended using the non-ASCII single quotation marks directly in doc strings, but this is now discouraged, since that leads to broken help string displays on terminals that don’t support displaying those characters.)
Help mode automatically creates a hyperlink when a documentation string uses a single-quoted symbol name, if the symbol has either a function or a variable definition. You do not need to do anything special to make use of this feature. However, when a symbol has both a function definition and a variable definition, and you want to refer to just one of them, you can specify which one by writing one of the words ‘variable’, ‘option’, ‘function’, or ‘command’, immediately before the symbol name. (Case makes no difference in recognizing these indicator words.) For example, if you write
This function sets the variable `buffer-file-name'.
then the hyperlink will refer only to the variable documentation of
buffer-file-name, and not to its function documentation.
If a symbol has a function definition and/or a variable definition, but those are irrelevant to the use of the symbol that you are documenting, you can write the words ‘symbol’ or ‘program’ before the symbol name to prevent making any hyperlink. For example,
If the argument KIND-OF-RESULT is the symbol `list', this function returns a list of all the objects that satisfy the criterion.
does not make a hyperlink to the documentation, irrelevant here, of the
function list.
Normally, no hyperlink is made for a variable without variable documentation. You can force a hyperlink for such variables by preceding them with one of the words ‘variable’ or ‘option’.
Hyperlinks for faces are only made if the face name is preceded or followed by the word ‘face’. In that case, only the face documentation will be shown, even if the symbol is also defined as a variable or as a function.
To make a hyperlink to Info documentation, write the single-quoted name of the Info node (or anchor), preceded by ‘info node’, ‘Info node’, ‘info anchor’ or ‘Info anchor’. The Info file name defaults to ‘emacs’. For example,
See Info node `Font Lock' and Info node `(elisp)Font Lock Basics'.
To make a hyperlink to a man page, write the single-quoted name of the man page, preceded by ‘Man page’, ‘man page’, or ‘man page for’. For example,
See the man page `chmod(1)' for details.
The Info documentation is always preferable to man pages, so be sure
to link to an Info manual where available. For example,
chmod is documented in the GNU Coreutils manual, so it is
better to link to that instead of the man page.
To link to a customization group, write the single-quoted name of the group, preceded by ‘customization group’ (the first character in each word is case-insensitive). For example,
See the customization group `whitespace' for details.
Finally, to create a hyperlink to URLs, write the single-quoted URL, preceded by ‘URL’. For example,
The GNU project website has more information (see URL `https://www.gnu.org/').
forward-char.
(This is normally ‘C-f’, but it may be some other character if the
user has moved key bindings.) See 文档中的按键绑定替换.
Each use of ‘\\[…]’ slows the display of the documentation string by a tiny amount. If you use a lot of them, these tiny slowdowns will add up, and might become tangible, especially on slow systems. So our recommendation is not to over-use them; e.g., try to avoid using more than one reference to the same command in the same doc string.
dired-find-file is:
In Dired, visit the file or directory named on this line.
defcustom. See 定义全局变量.
nil values are equivalent and indicate explicitly what
nil and non-nil mean.
The argument FOO can be either a number \(a buffer position) or a string (a file name).
This avoids a bug in Emacs versions older than 27.1, where the ‘(’ was treated as the start of a defun (see Defuns in The GNU Emacs Manual). If you do not anticipate anyone editing your code with older Emacs versions, there is no need for this work-around.
We recommend these conventions for comments:
Comments that start with a single semicolon, ‘;’, should all be aligned to the same column on the right of the source code. Such comments usually explain how the code on that line does its job. For example:
(setq base-version-list ; There was a base
(assoc (substring fn 0 start-vn) ; version to which
file-version-assoc-list)) ; this looks like
; a subversion.
Comments that start with two semicolons, ‘;;’, should be aligned to the same level of indentation as the code. Such comments usually describe the purpose of the following lines or the state of the program at that point. For example:
(prog1 (setq auto-fill-function
...
...
;; Update mode line.
(force-mode-line-update)))
We also normally use two semicolons for comments outside functions.
;; This Lisp code is run in Emacs when it is to operate as ;; a server for other processes.
If a function has no documentation string, it should instead have a two-semicolon comment right before the function, explaining what the function does and how to call it properly. Explain precisely what each argument means and how the function interprets its possible values. It is much better to convert such comments to documentation strings, though.
Comments that start with three (or more) semicolons, ‘;;;’, should start at the left margin. We use them for comments that should be considered a heading by Outline minor mode. By default, comments starting with at least three semicolons (followed by a single space and a non-whitespace character) are considered section headings, comments starting with two or fewer are not.
(Historically, triple-semicolon comments have also been used for commenting out lines within a function, but this use is discouraged in favor of using just two semicolons. This also applies when commenting out entire functions; when doing that use two semicolons as well.)
Three semicolons are used for top-level sections, four for sub-sections, five for sub-sub-sections and so on.
Typically libraries have at least four top-level sections. For example when the bodies of all of these sections are hidden:
;;; backquote.el --- implement the ` Lisp construct... ;;; Commentary:... ;;; Code:... ;;; backquote.el ends here
(In a sense the last line is not a section heading as it must never be followed by any text; after all it marks the end of the file.)
For longer libraries it is advisable to split the code into multiple sections. This can be done by splitting the ‘Code:’ section into multiple sub-sections. Even though that was the only recommended approach for a long time, many people have chosen to use multiple top-level code sections instead. You may chose either style.
Using multiple top-level code sections has the advantage that it avoids introducing an additional nesting level but it also means that the section named ‘Code’ does not contain all the code, which is awkward. To avoid that, you should put no code at all inside that section; that way it can be considered a separator instead of a section heading.
Finally, we recommend that you don’t end headings with a colon or any other punctuation for that matter. For historic reasons the ‘Code:’ and ‘Commentary:’ headings end with a colon, but we recommend that you don’t do the same for other headings anyway.
Generally speaking, the M-; (comment-dwim) command
automatically starts a comment of the appropriate type; or indents an
existing comment to the right place, depending on the number of
semicolons.
See Manipulating Comments in The GNU Emacs Manual.
Emacs has conventions for using special comments in Lisp libraries to divide them into sections and give information such as who wrote them. Using a standard format for these items makes it easier for tools (and people) to extract the relevant information. This section explains these conventions, starting with an example:
;;; foo.el --- Support for the Foo programming language -*- lexical-binding: t; -*- ;; Copyright (C) 2010-2025 Your Name
;; Author: Your Name <[email protected]> ;; Maintainer: Someone Else <[email protected]> ;; Created: 14 Jul 2010
;; Keywords: languages ;; URL: https://example.com/foo ;; This file is not part of GNU Emacs. ;; This file is free software... ... ;; along with this file. If not, see <https://www.gnu.org/licenses/>.
The very first line should have this format:
;;; filename --- description -*- lexical-binding: t; -*-
The description should be contained in one line. If the file needs to
set more variables in the ‘-*-’ specification, add it after
lexical-binding. If this would make the first line too long, use
a Local Variables section at the end of the file.
The copyright notice usually lists your name (if you wrote the file). If you have an employer who claims copyright on your work, you might need to list them instead. Do not say that the copyright holder is the Free Software Foundation (or that the file is part of GNU Emacs) unless your file has been accepted into the Emacs distribution or GNU ELPA. For more information on the form of copyright and license notices, see the guide on the GNU website.
After the copyright notice come several header comment lines, each beginning with ‘;; header-name:’. Here is a table of the conventional possibilities for header-name:
This header states the name and email address of at least the principal
author of the library. If there are multiple authors, list them on
continuation lines led by ;; and a tab or at least two spaces.
We recommend including a contact email address, of the form
‘<…>’. For example:
;; Author: Your Name <[email protected]> ;; Someone Else <[email protected]> ;; Another Person <[email protected]>
This header has the same format as the Author header. It lists the person(s) who currently maintain(s) the file (respond to bug reports, etc.).
If there is no Maintainer header, the person(s) in the Author header is/are presumed to be the maintainer(s). Some files in Emacs use ‘[email protected]’ for the maintainer, which means the author is no longer responsible for the file, and that it is maintained as part of Emacs.
This optional line gives the original creation date of the file, and is for historical interest only.
If you wish to record version numbers for the individual Lisp program, put them in this line. Lisp files distributed with Emacs generally do not have a ‘Version’ header, since the version number of Emacs itself serves the same purpose. If you are distributing a collection of multiple files, we recommend not writing the version in every file, but only the main one.
This line lists keywords for the finder-by-keyword help command.
Please use that command to see a list of the meaningful keywords. The
command M-x checkdoc-package-keywords RET will find and display
any keywords that are not in finder-known-keywords. If you set
the variable checkdoc-package-keywords-flag non-nil,
checkdoc commands will include the keyword verification in its checks.
This field is how people will find your package when they’re looking for things by topic. To separate the keywords, you can use spaces, commas, or both.
The name of this field is unfortunate, since people often assume it is the place to write arbitrary keywords that describe their package, rather than just the relevant Finder keywords.
These lines state the website of the library.
If ‘Version’ is not suitable for use by the package manager, then
a package can define ‘Package-Version’; it will be used instead.
This is handy if ‘Version’ is an RCS id or something else that
cannot be parsed by version-to-list. See Packaging Basics.
If this exists, it names packages on which the current package depends for proper operation. See Packaging Basics. This is used by the package manager both at download time (to ensure that a complete set of packages is downloaded) and at activation time (to ensure that a package is only activated if all its dependencies have been).
Its format is a list of lists on a single line. The car of
each sub-list is the name of a package, as a symbol. The cadr
of each sub-list is the minimum acceptable version number, as a string
that can be parsed by version-to-list. An entry that lacks a
version (i.e., an entry which is just a symbol, or a sub-list of one
element) is equivalent to entry with version "0". For instance:
;; Package-Requires: ((gnus "1.0") (bubbles "2.7.2") cl-lib (seq))
Packages that don’t need to support Emacs versions older than Emacs 27 can have the ‘Package-Requires’ header split across multiple lines, like this:
;; Package-Requires: ((emacs "27.1") ;; (compat "29.1.4.1"))
Note that with this format, you still need to start the list on the same line as ‘Package-Requires’.
The package code automatically defines a package named ‘emacs’ with the version number of the currently running Emacs. This can be used to require a minimal version of Emacs for a package.
Just about every Lisp library ought to have the ‘Author’ and ‘Keywords’ header comment lines. Use the others if they are appropriate. You can also put in header lines with other header names—they have no standard meanings, so they can’t do any harm.
We use additional stylized comments to subdivide the contents of the library file. These should be separated from anything else by blank lines. Here is a table of them:
This begins introductory comments that explain how the library works. It should come right after the copying permissions, and is terminated by one of the comment lines described below: ‘Change Log’, ‘History’ or ‘Code’. This text is used by the Finder package, so it should make sense in that context.
This begins an optional log of changes to the file over time. Don’t put too much information in this section—it is better to keep the detailed logs in a version control system (as Emacs does) or in a separate ChangeLog file. ‘History’ is an alternative to ‘Change Log’.
This begins the actual code of the program.
This is the footer line; it appears at the very end of the file. Its purpose is to enable people to detect truncated versions of the file from the lack of a footer line.
This chapter describes how the runnable Emacs executable is dumped with the preloaded Lisp libraries in it, how storage is allocated, and some internal aspects of GNU Emacs that may be of interest to C programmers.
This section explains the steps involved in building the Emacs executable. You don’t have to know this material to build and install Emacs, since the makefiles do all these things automatically. This information is pertinent to Emacs developers.
Building Emacs requires GNU Make version 3.81 or later.
Compilation of the C source files in the src directory produces an executable file called temacs, also called a bare impure Emacs. It contains the Emacs Lisp interpreter and I/O routines, but not the editing commands.
The command temacs -l loadup would run temacs
and direct it to load loadup.el. The loadup library
loads additional Lisp libraries, which set up the normal Emacs editing
environment. After this step, the Emacs executable is no longer
bare.
Because it takes some time to load the standard Lisp files, the
temacs executable usually isn’t run directly by users.
Instead, one of the last steps of building Emacs runs the command
‘temacs -batch -l loadup --temacs=dump-method’. The
special option --temacs tells temacs how to record
all the standard preloaded Lisp functions and variables, so that when
you subsequently run Emacs, it will start much faster. The
--temacs option requires an argument dump-method, which
can be one of the following:
Record the preloaded Lisp data in a dump file. This
method produces an additional data file which Emacs will load at
startup. The produced dump file is usually called emacs.pdmp,
and is installed in the Emacs exec-directory (see 帮助函数). This method is the most preferred one, as it does not
require Emacs to employ any special techniques of memory allocation,
which might get in the way of various memory-layout techniques used by
modern systems to enhance security and privacy.
Like ‘pdump’, but used while bootstrapping Emacs, when no previous Emacs binary and no *.elc byte-compiled Lisp files are available. The produced dump file is usually named bootstrap-emacs.pdmp in this case.
This method causes temacs to dump out an executable program,
called emacs, which has all the standard Lisp files already
preloaded into it. (The ‘-batch’ argument prevents
temacs from trying to initialize any of its data on the
terminal, so that the tables of terminal information are empty in the
dumped Emacs.) This method is also known as unexec, because it
produces a program file from a running process, and thus is in some
sense the opposite of executing a program to start a process.
Although this method was the way that Emacs traditionally saved its
state, it is now deprecated.
Like ‘dump’, but used when bootstrapping Emacs with the
unexec method.
The dumped emacs executable (also called a pure Emacs)
is the one which is installed. If the portable dumper was used to
build Emacs, the emacs executable is actually an exact copy of
temacs, and the corresponding emacs.pdmp file is
installed as well. The variable preloaded-file-list stores a
list of the preloaded Lisp files recorded in the dump file or
in the dumped Emacs executable. If you port Emacs to a new operating
system, and are not able to implement dumping of any kind, then Emacs
must load loadup.el each time it starts.
By default the dumped emacs executable records details such
as the build time and host name. Use the
--disable-build-details option of configure to
suppress these details, so that building and installing Emacs twice
from the same sources is more likely to result in identical copies of
Emacs.
You can specify additional files to preload by writing a library named site-load.el that loads them. You may need to rebuild Emacs with an added definition
#define SITELOAD_PURESIZE_EXTRA n
to make n added bytes of pure space to hold the additional files; see src/puresize.h. (Try adding increments of 20000 until it is big enough.) However, the advantage of preloading additional files decreases as machines get faster. On modern machines, it is usually not advisable.
After loadup.el reads site-load.el, it finds the
documentation strings for primitive and preloaded functions (and
variables) in the file etc/DOC where they are stored, by
calling Snarf-documentation (see Accessing Documentation).
You can specify other Lisp expressions to execute just before dumping by putting them in a library named site-init.el. This file is executed after the documentation strings are found.
If you want to preload function or variable definitions, there are three ways you can do this and make their documentation strings accessible when you subsequently run Emacs:
nil value for byte-compile-dynamic-docstrings
as a local variable in each of these files, and load them with either
site-load.el or site-init.el. (This method has the
drawback that the documentation strings take up space in Emacs all the
time.)
It is not advisable to put anything in site-load.el or
site-init.el that would alter any of the features that users
expect in an ordinary unmodified Emacs. If you feel you must override
normal features for your site, do it with default.el, so that
users can override your changes if they wish. See Summary: Sequence of Actions at Startup.
Note that if either site-load.el or site-init.el changes
load-path, the changes will be lost after dumping.
See 库搜索. To make a permanent change to
load-path, use the --enable-locallisppath option
of configure.
In a package that can be preloaded, it is sometimes necessary (or
useful) to delay certain evaluations until Emacs subsequently starts
up. The vast majority of such cases relate to the values of
customizable variables. For example, tutorial-directory is a
variable defined in startup.el, which is preloaded. The default
value is set based on data-directory. The variable needs to
access the value of data-directory when Emacs starts, not when
it is dumped, because the Emacs executable has probably been installed
in a different location since it was dumped.
This function delays the initialization of symbol to the next
Emacs start. You normally use this function by specifying it as the
:initialize property of a customizable variable. (The argument
value is unused, and is provided only for compatibility with the
form Custom expects.)
In the unlikely event that you need a more general functionality than
custom-initialize-delay provides, you can use
before-init-hook (see Summary: Sequence of Actions at Startup).
This function dumps the current state of Emacs into a dump
file to-file, using the pdump method. Normally, the
dump file is called emacs-name.dmp, where
emacs-name is the name of the Emacs executable file. The
optional argument track-referrers, if non-nil, causes the
portable dumper to keep additional information to help track
down the provenance of object types that are not yet supported by the
pdump method.
Although the portable dumper code can run on many platforms, the dump files that it produces are not portable—they can be loaded only by the Emacs executable that dumped them.
If you want to use this function in an Emacs that was already dumped, you must run Emacs with the ‘-batch’ option.
If you’re including ‘.el’ files in the dumped Emacs and that
‘.el’ file has code that is normally run at load time, that code
won’t be run when Emacs starts after dumping. To help work around
that problem, you can put functions on the
after-pdump-load-hook hook. This hook is run when starting
Emacs.
This function dumps the current state of Emacs into an executable file
to-file, using the unexec method. It takes symbols from
from-file (this is normally the executable file temacs).
This function cannot be used in an Emacs that was already dumped.
This function is deprecated, and by default Emacs is built without
unexec support so this function is not available.
If the current Emacs session restored its state from a dump
file, this function returns information about the dump file and the
time it took to restore the Emacs state. The value is an alist
((dumped-with-pdumper . t) (load-time . time) (dump-file-name . file)),
where file is the name of the dump file, and time is the
time in seconds it took to restore the state from the dump file.
If the current session was not restored from a dump file, the
value is nil.
Emacs Lisp uses two kinds of storage for user-created Lisp objects: normal storage and pure storage. Normal storage is where all the new data created during an Emacs session are kept (see Garbage Collection). Pure storage is used for certain data in the preloaded standard Lisp files—data that should never change during actual use of Emacs.
Pure storage is allocated only while temacs is loading the
standard preloaded Lisp libraries. In the file emacs, it is
marked as read-only (on operating systems that permit this), so that
the memory space can be shared by all the Emacs jobs running on the
machine at once. Pure storage is not expandable; a fixed amount is
allocated when Emacs is compiled, and if that is not sufficient for
the preloaded libraries, temacs allocates dynamic memory for
the part that didn’t fit. If Emacs will be dumped using the
pdump method (see Building Emacs), the pure-space overflow
is of no special importance (it just means some of the preloaded stuff
cannot be shared with other Emacs jobs). However, if Emacs will be
dumped using the now obsolete unexec method, the resulting
image will work, but garbage collection (see Garbage Collection)
is disabled in this situation, causing a memory leak. Such an
overflow normally won’t happen unless you try to preload additional
libraries or add features to the standard ones. Emacs will display a
warning about the overflow when it starts, if it was dumped using
unexec. If this happens, you should increase the compilation
parameter SYSTEM_PURESIZE_EXTRA in the file
src/puresize.h and rebuild Emacs.
This function makes a copy in pure storage of object, and returns it. It copies a string by simply making a new string with the same characters, but without text properties, in pure storage. It recursively copies the contents of vectors and cons cells. It does not make copies of other objects such as symbols, but just returns them unchanged. It signals an error if asked to copy markers.
This function is a no-op except while Emacs is being built and dumped; it is usually called only in preloaded Lisp files.
The value of this variable is the number of bytes of pure storage allocated so far. Typically, in a dumped Emacs, this number is very close to the total amount of pure storage available—if it were not, we would preallocate less.
This variable determines whether defun should make a copy of the
function definition in pure storage. If it is non-nil, then the
function definition is copied into pure storage.
This flag is t while loading all of the basic functions for
building Emacs initially (allowing those functions to be shareable and
non-collectible). Dumping Emacs as an executable always writes
nil in this variable, regardless of the value it actually has
before and after dumping.
You should not change this flag in a running Emacs.
When a program creates a list or the user defines a new function (such as by loading a library), that data is placed in normal storage. If normal storage runs low, then Emacs asks the operating system to allocate more memory. Different types of Lisp objects, such as symbols, cons cells, small vectors, markers, etc., are segregated in distinct blocks in memory. (Large vectors, long strings, buffers and certain other editing types, which are fairly large, are allocated in individual blocks, one per object; small strings are packed into blocks of 8k bytes, and small vectors are packed into blocks of 4k bytes).
Beyond the basic vector, a lot of objects like markers, overlays and
buffers are managed as if they were vectors. The corresponding C data
structures include the union vectorlike_header field whose
size member contains the subtype enumerated by enum pvec_type
and an information about how many Lisp_Object fields this structure
contains and what the size of the rest data is. This information is
needed to calculate the memory footprint of an object, and used
by the vector allocation code while iterating over the vector blocks.
It is quite common to use some storage for a while, then release it by (for example) killing a buffer or deleting the last pointer to an object. Emacs provides a garbage collector to reclaim this abandoned storage. The garbage collector operates, in essence, by finding and marking all Lisp objects that are still accessible to Lisp programs. To begin with, it assumes all the symbols, their values and associated function definitions, and any data presently on the stack, are accessible. Any objects that can be reached indirectly through other accessible objects are also accessible, but this calculation is done “conservatively”, so it may slightly overestimate how many objects that are accessible.
When marking is finished, all objects still unmarked are garbage. No matter what the Lisp program or the user does, it is impossible to refer to them, since there is no longer a way to reach them. Their space might as well be reused, since no one will miss them. The second (sweep) phase of the garbage collector arranges to reuse them. (But since the marking was done “conservatively”, not all unused objects are guaranteed to be garbage-collected by any one sweep.)
The sweep phase puts unused cons cells onto a free list for future allocation; likewise for symbols and markers. It compacts the accessible strings so they occupy fewer 8k blocks; then it frees the other 8k blocks. Unreachable vectors from vector blocks are coalesced to create largest possible free areas; if a free area spans a complete 4k block, that block is freed. Otherwise, the free area is recorded in a free list array, where each entry corresponds to a free list of areas of the same size. Large vectors, buffers, and other large objects are allocated and freed individually.
Common Lisp note: Unlike other Lisps, GNU Emacs Lisp does not call the garbage collector when the free list is empty. Instead, it simply requests the operating system to allocate more storage, and processing continues until
gc-cons-thresholdbytes have been used.This means that you can make sure that the garbage collector will not run during a certain portion of a Lisp program by calling the garbage collector explicitly just before it (provided that portion of the program does not use so much space as to force a second garbage collection).
This command runs a garbage collection, and returns information on
the amount of space in use. (Garbage collection can also occur
spontaneously if you use more than gc-cons-threshold bytes of
Lisp data since the previous garbage collection.)
garbage-collect returns a list with information on amount of space in
use, where each entry has the form ‘(name size used)’
or ‘(name size used free)’. In the entry,
name is a symbol describing the kind of objects this entry represents,
size is the number of bytes used by each one, used is the number
of those objects that were found live in the heap, and optional free is
the number of those objects that are not live but that Emacs keeps around for
future allocations. So an overall result is:
((consescons-size used-conses free-conses) (symbolssymbol-size used-symbols free-symbols) (stringsstring-size used-strings free-strings) (string-bytesbyte-size used-bytes) (vectorsvector-size used-vectors) (vector-slotsslot-size used-slots free-slots) (floatsfloat-size used-floats free-floats) (intervalsinterval-size used-intervals free-intervals) (buffersbuffer-size used-buffers) (heapunit-size total-size free-size))
Here is an example:
(garbage-collect)
⇒ ((conses 16 49126 8058) (symbols 48 14607 0)
(strings 32 2942 2607)
(string-bytes 1 78607) (vectors 16 7247)
(vector-slots 8 341609 29474) (floats 8 71 102)
(intervals 56 27 26) (buffers 944 8)
(heap 1024 11715 2678))
Below is a table explaining each element. Note that last heap entry
is optional and present only if an underlying malloc implementation
provides mallinfo function.
Internal size of a cons cell, i.e., sizeof (struct Lisp_Cons).
The number of cons cells in use.
The number of cons cells for which space has been obtained from the operating system, but that are not currently being used.
Internal size of a symbol, i.e., sizeof (struct Lisp_Symbol).
The number of symbols in use.
The number of symbols for which space has been obtained from the operating system, but that are not currently being used.
Internal size of a string header, i.e., sizeof (struct Lisp_String).
The number of string headers in use.
The number of string headers for which space has been obtained from the operating system, but that are not currently being used.
This is used for convenience and equals to sizeof (char).
The total size of all string data in bytes.
Size in bytes of a vector of length 1, including its header.
The number of vector headers allocated from the vector blocks.
Internal size of a vector slot, always equal to sizeof (Lisp_Object).
The number of slots in all used vectors. Slot counts might include some or all overhead from vector headers, depending on the platform.
The number of free slots in all vector blocks.
Internal size of a float object, i.e., sizeof (struct Lisp_Float).
(Do not confuse it with the native platform float or double.)
The number of floats in use.
The number of floats for which space has been obtained from the operating system, but that are not currently being used.
Internal size of an interval object, i.e., sizeof (struct interval).
The number of intervals in use.
The number of intervals for which space has been obtained from the operating system, but that are not currently being used.
Internal size of a buffer, i.e., sizeof (struct buffer).
(Do not confuse with the value returned by buffer-size function.)
The number of buffer objects in use. This includes killed buffers
invisible to users, i.e., all buffers in all_buffers list.
The unit of heap space measurement, always equal to 1024 bytes.
Total heap size, in unit-size units.
Heap space which is not currently used, in unit-size units.
If there was overflow in pure space (see Pure Storage), and Emacs
was dumped using the (now obsolete) unexec method
(see Building Emacs), then garbage-collect returns
nil, because a real garbage collection cannot be done in that
case.
If this variable is non-nil, Emacs displays a message at the
beginning and end of garbage collection. The default value is
nil.
This is a normal hook that is run at the end of garbage collection. Garbage collection is inhibited while the hook functions run, so be careful writing them.
The value of this variable is the number of bytes of storage that must
be allocated for Lisp objects after one garbage collection in order to
trigger another garbage collection. You can use the result returned by
garbage-collect to get an information about size of the particular
object type; space allocated to the contents of buffers does not count.
The initial threshold value is GC_DEFAULT_THRESHOLD, defined in
alloc.c. Since it’s defined in word_size units, the
value is 400,000 for the default 32-bit configuration, and 800,000 for
the 64-bit one and for 32-bit builds configured with the
--with-wide-int option. If you specify a larger value, garbage
collection will happen less often. This reduces the amount of time
spent garbage collecting (so Lisp programs will run faster between
cycles of garbage collection that happen more rarely), but increases
total memory use. You may want to do this when running a program that
creates lots of Lisp data, especially if you need it to run faster.
However, we recommend against increasing the threshold for prolonged
periods of time, and advise that you never set it higher than needed for
the program to run in reasonable time. Using thresholds higher than
necessary could potentially cause higher system-wide memory pressure,
and also make each garbage-collection cycle take much more time, and
should therefore be avoided.
You can make collections more frequent by specifying a smaller value, down
to 1/10th of GC_DEFAULT_THRESHOLD. A value less than this minimum
will remain in effect only until the subsequent garbage collection, at which
time garbage-collect will set the threshold back to the minimum.
The value of this variable specifies the amount of consing before a
garbage collection occurs, as a fraction of the current heap size.
This criterion and gc-cons-threshold apply in parallel, and
garbage collection occurs only when both criteria are satisfied.
As the heap size increases, the time to perform a garbage collection increases. Thus, it can be desirable to do them less frequently in proportion.
The initial percentage value is 0.1 in interactive sessions and while dumping Emacs (see Building Emacs), and 1.0 in non-interactive (a.k.a. “batch”) sessions.
As with gc-cons-threshold, do not enlarge this more than
necessary, and never for prolonged periods of time.
Control over the garbage collector via gc-cons-threshold and
gc-cons-percentage is only approximate. Although Emacs checks
for threshold exhaustion regularly, for efficiency reasons it does not
do so immediately after every change to the heap or to
gc-cons-threshold or gc-cons-percentage, so exhausting
the threshold does not immediately trigger garbage collection. Also,
for efficiency in threshold calculations Emacs approximates the heap
size, which counts the bytes used by currently-accessible objects in
the heap.
The value returned by garbage-collect describes the amount of
memory used by Lisp data, broken down by data type. By contrast, the
function memory-limit provides information on the total amount of
memory Emacs is currently using.
This function returns an estimate of the total amount of bytes of virtual memory that Emacs is currently using, divided by 1024. You can use this to get a general idea of how your actions affect the memory usage.
This variable is t if Emacs is nearly out of memory for Lisp
objects, and nil otherwise.
This returns a list of numbers that count the number of objects created in this Emacs session. Each of these counters increments for a certain kind of object. See the documentation string for details.
This functions returns an amount of total system memory and how much
of it is free. On an unsupported system, the value may be nil.
If default-directory points to a remote host, memory
information of that host is returned.
This variable contains the total number of garbage collections done so far in this Emacs session.
This variable contains the total number of seconds of elapsed time during garbage collection so far in this Emacs session, as a floating-point number.
It can sometimes be useful to see where Emacs is using memory (in various variables, buffers, and caches). This command will open a new buffer (called ‘"*Memory Report*"’) that will give an overview, in addition to listing the “largest” buffers and variables.
All the data here is approximate, because there’s really no consistent way to compute the size of a variable. For instance, two variables may share parts of a data structure, and this will be counted twice, but this command may still give a useful high-level overview of which parts of Emacs are using memory.
The garbage collector described above is used to manage data visible
from Lisp programs, as well as most of the data internally used by the
Lisp interpreter. Sometimes it may be useful to allocate temporary
internal objects using the C stack of the interpreter. This can help
performance, as stack allocation is typically faster than using heap
memory to allocate and the garbage collector to free. The downside is
that using such objects after they are freed results in undefined
behavior, so uses should be well thought out and carefully debugged by
using the GC_CHECK_MARKED_OBJECTS feature (see
src/alloc.c). In particular, stack-allocated objects should
never be made visible to user Lisp code.
Currently, cons cells and strings can be allocated this way. This
is implemented by C macros like AUTO_CONS and
AUTO_STRING that define a named Lisp_Object with block
lifetime. These objects are not freed by the garbage collector;
instead, they have automatic storage duration, i.e., they are
allocated like local variables and are automatically freed at the end
of execution of the C block that defined the object.
For performance reasons, stack-allocated strings are limited to
ASCII characters, and many of these strings are immutable,
i.e., calling ASET on them produces undefined behavior.
These functions and variables give information about the total amount
of memory allocation that Emacs has done, broken down by data type.
Note the difference between these and the values returned by
garbage-collect; those count objects that currently exist, but
these count the number or size of all allocations, including those for
objects that have since been freed.
The total number of cons cells that have been allocated so far in this Emacs session.
The total number of floats that have been allocated so far in this Emacs session.
The total number of vector cells that have been allocated so far in this Emacs session. This includes vector-like objects such as markers and overlays, plus certain objects not visible to users.
The total number of symbols that have been allocated so far in this Emacs session.
The total number of string characters that have been allocated so far in this session.
The total number of intervals that have been allocated so far in this Emacs session.
The total number of strings that have been allocated so far in this Emacs session.
The C part of Emacs is portable to C99 or later: later C features such as ‘<stdckdint.h>’ and ‘[[noreturn]]’ are not used without a check, typically at configuration time, and the Emacs build procedure provides a substitute implementation if necessary. Some later features, such as anonymous structures and unions, are too difficult to emulate, so they are avoided entirely.
At some point in the future the base C dialect will no doubt change to something later than C99.
Lisp primitives are Lisp functions implemented in C. The details of interfacing the C function so that Lisp can call it are handled by a few C macros. The only way to really understand how to write new C code is to read the source, but we can explain some things here.
An example of a special form is the definition of or, from
eval.c. (An ordinary function would have the same general
appearance.)
DEFUN ("or", For, Sor, 0, UNEVALLED, 0,
doc: /* Eval args until one of them yields non-nil,
then return that value.
The remaining args are not evalled at all.
If all args return nil, return nil.
usage: (or CONDITIONS...) */)
(Lisp_Object args)
{
Lisp_Object val = Qnil;
while (CONSP (args))
{
val = eval_sub (XCAR (args));
if (!NILP (val))
break;
args = XCDR (args);
maybe_quit ();
}
return val; }
Let’s start with a precise explanation of the arguments to the
DEFUN macro. Here is a template for them:
DEFUN (lname, fname, sname, min, max, interactive, doc)
This is the name of the Lisp symbol to define as the function name; in
the example above, it is or.
This is the C function name for this function. This is the name that
is used in C code for calling the function. The name is, by
convention, ‘F’ prepended to the Lisp name, with all dashes
(‘-’) in the Lisp name changed to underscores. Thus, to call
this function from C code, call For.
This is a C variable name to use for a structure that holds the data for the subr object that represents the function in Lisp. This structure conveys the Lisp symbol name to the initialization routine that will create the symbol and store the subr object as its definition. By convention, this name is always fname with ‘F’ replaced with ‘S’.
This is the minimum number of arguments that the function requires. The
function or allows a minimum of zero arguments.
This is the maximum number of arguments that the function accepts, if
there is a fixed maximum. Alternatively, it can be UNEVALLED,
indicating a special form that receives unevaluated arguments, or
MANY, indicating an unlimited number of evaluated arguments (the
equivalent of &rest). Both UNEVALLED and MANY are
macros. If max is a number, it must be more than min but
less than 8.
This is an interactive specification, a string such as might be used
as the argument of interactive in a Lisp function
(see 使用 interactive). In the case
of or, it is 0 (a null pointer), indicating that or
cannot be called interactively. A value of "" indicates a
function that should receive no arguments when called interactively.
If the value begins with a ‘"(’, the string is evaluated as a
Lisp form. For example:
DEFUN ("foo", Ffoo, Sfoo, 0, 3,
"(list (read-char-by-name \"Insert character: \")\
(prefix-numeric-value current-prefix-arg)\
t)",
doc: /* ... */)
This is the documentation string. It uses C comment syntax rather than C string syntax because comment syntax requires nothing special to include multiple lines. The ‘doc:’ identifies the comment that follows as the documentation string. The ‘/*’ and ‘*/’ delimiters that begin and end the comment are not part of the documentation string.
If the last line of the documentation string begins with the keyword ‘usage:’, the rest of the line is treated as the argument list for documentation purposes. This way, you can use different argument names in the documentation string from the ones used in the C code. ‘usage:’ is required if the function has an unlimited number of arguments.
Some primitives have multiple definitions, one per platform (e.g.,
x-create-frame). In such cases, rather than writing the
same documentation string in each definition, only one definition has
the actual documentation. The others have placeholders beginning with
‘SKIP’, which are ignored by the function that parses the
DOC file.
All the usual rules for documentation strings in Lisp code (see Tips for Documentation Strings) apply to C code documentation strings too.
The documentation string can be followed by a list of C function attributes for the C function that implements the primitive, like this:
DEFUN ("bar", Fbar, Sbar, 0, UNEVALLED, 0
doc: /* ... */
attributes: attr1 attr2 ...)
You can specify more than a single attribute, one after the other. Currently, only the following attributes are recognized:
noreturnDeclares the C function as one that never returns. This corresponds
to C23’s [[noreturn]], to C11’s _Noreturn, and to GCC’s
__attribute__ ((__noreturn__)) (see Function
Attributes in Using the GNU Compiler Collection). (Internally,
Emacs’s own C code uses _Noreturn as it can be defined as a
macro on C platforms that do not support it.)
constDeclares that the function does not examine any values except its
arguments, and has no effects except the return value. This
corresponds to C23’s [[unsequenced]] and to GCC’s
__attribute__ ((__const__)).
noinlineThis corresponds to __attribute__ ((__noinline__))
attribute of GCC, which prevents the function from being considered
for inlining. This might be needed, e.g., to countermand effects of
link-time optimizations on stack-based variables.
After the call to the DEFUN macro, you must write the
argument list for the C function, including the types for the
arguments. If the primitive accepts a fixed maximum number of Lisp
arguments, there must be one C argument for each Lisp argument, and
each argument must be of type Lisp_Object. (Various macros and
functions for creating values of type Lisp_Object are declared
in the file lisp.h.) If the primitive is a special form, it
must accept a Lisp list containing its unevaluated Lisp arguments as a
single argument of type Lisp_Object. If the primitive has no
upper limit on the number of evaluated Lisp arguments, it must have
exactly two C arguments: the first is the number of Lisp arguments,
and the second is the address of a block containing their values.
These have types ptrdiff_t and Lisp_Object *,
respectively. Since Lisp_Object can hold any Lisp object of
any data type, you can determine the actual data type only at run
time; so if you want a primitive to accept only a certain type of
argument, you must check the type explicitly using a suitable
predicate (see 类型谓词).
Within the function For itself, the local variable
args refers to objects controlled by Emacs’s stack-marking
garbage collector. Although the garbage collector does not reclaim
objects reachable from C Lisp_Object stack variables, it may
move some of the components of an object, such as the contents of a
string or the text of a buffer. Therefore, functions that access
these components must take care to refetch their addresses after
performing Lisp evaluation. This means that instead of keeping C
pointers to string contents or buffer text, the code should keep the
buffer or string position, and recompute the C pointer from the
position after performing Lisp evaluation. Lisp evaluation can occur
via calls to eval_sub or Feval, either directly or
indirectly.
Note the call to maybe_quit inside the loop: this function
checks whether the user pressed C-g, and if so, aborts the
processing. You should do that in any loop that can potentially
require a large number of iterations; in this case, the list of
arguments could be very long. This increases Emacs responsiveness and
improves user experience.
You must not use C initializers for static or global variables unless the variables are never written once Emacs is dumped. These variables with initializers are allocated in an area of memory that becomes read-only (on certain operating systems) as a result of dumping Emacs. See Pure Storage.
Defining the C function is not enough to make a Lisp primitive available; you must also create the Lisp symbol for the primitive and store a suitable subr object in its function cell. The code looks like this:
defsubr (&sname);
Here sname is the name you used as the third argument to DEFUN.
If you add a new primitive to a file that already has Lisp primitives
defined in it, find the function (near the end of the file) named
syms_of_something, and add the call to defsubr
there. If the file doesn’t have this function, or if you create a new
file, add to it a syms_of_filename (e.g.,
syms_of_myfile). Then find the spot in emacs.c where all
of these functions are called, and add a call to
syms_of_filename there.
The function syms_of_filename is also the place to define
any C variables that are to be visible as Lisp variables.
DEFVAR_LISP makes a C variable of type Lisp_Object visible
in Lisp. DEFVAR_INT makes a C variable of type int
visible in Lisp with a value that is always an integer.
DEFVAR_BOOL makes a C variable of type int visible in Lisp
with a value that is either t or nil. Note that variables
defined with DEFVAR_BOOL are automatically added to the list
byte-boolean-vars used by the byte compiler.
These macros all expect three arguments:
lnameThe name of the variable to be used by Lisp programs.
vnameThe name of the variable in the C sources.
docThe documentation for the variable, as a C comment. See 文档基础, for more details.
By convention, when defining variables of a “native” type
(int and bool), the name of the C variable is the name
of the Lisp variable with - replaced by _. When the
variable has type Lisp_Object, the convention is to also prefix
the C variable name with V. This is an example:
DEFVAR_INT ("my-int-variable", my_int_variable,
doc: /* An integer variable. */);
DEFVAR_LISP ("my-lisp-variable", Vmy_lisp_variable,
doc: /* A Lisp variable. */);
There are situations in Lisp where you need to refer to the symbol
itself rather than the value of that symbol. One such case is when
temporarily overriding the value of a variable, which in Lisp is done
with let. In C sources, this is done by defining a
corresponding, constant symbol, and using specbind. By
convention, Qmy_lisp_variable corresponds to
Vmy_lisp_variable; to define it, use the DEFSYM macro.
DEFSYM (Qmy_lisp_variable, "my-lisp-variable");
To perform the actual binding:
specbind (Qmy_lisp_variable, Qt);
In Lisp, symbols sometimes need to be quoted. To achieve the same
effect in C, you again use the corresponding constant symbol
Qmy_lisp_variable. For example, when creating a buffer-local
variable (see 缓冲区局部变量) in Lisp, you would write:
(make-variable-buffer-local 'my-lisp-variable)
In C, the corresponding code uses Fmake_variable_buffer_local in
combination with DEFSYM:
DEFSYM (Qmy_lisp_variable, "my-lisp-variable"); Fmake_variable_buffer_local (Qmy_lisp_variable);
If you want to make a Lisp variable that is defined in C behave
like one declared with defcustom, add an appropriate entry to
cus-start.el. See 定义自定义变量, for a description of
the format to use.
If you directly define a file-scope C variable of type
Lisp_Object, you must protect it from garbage-collection by
calling staticpro in syms_of_filename, like this:
staticpro (&variable);
Here is another example function, with more complicated arguments. This comes from the code in window.c, and it demonstrates the use of macros and functions to manipulate Lisp objects.
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
Scoordinates_in_window_p, 2, 2, 0,
doc: /* Return non-nil if COORDINATES are in WINDOW.
...
or `right-margin' is returned. */)
(register Lisp_Object coordinates, Lisp_Object window)
{
struct window *w;
struct frame *f;
int x, y;
Lisp_Object lx, ly;
w = decode_live_window (window); f = XFRAME (w->frame); CHECK_CONS (coordinates); lx = Fcar (coordinates); ly = Fcdr (coordinates); CHECK_NUMBER (lx); CHECK_NUMBER (ly); x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f); y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
switch (coordinates_in_window (w, x, y))
{
case ON_NOTHING: /* NOT in window at all. */
return Qnil;
...
case ON_MODE_LINE: /* In mode line of window. */
return Qmode_line;
...
case ON_SCROLL_BAR: /* On scroll-bar of window. */
/* Historically we are supposed to return nil in this case. */
return Qnil;
default:
emacs_abort ();
}
}
Note that C code cannot call functions by name unless they are defined
in C. The way to call a function written in Lisp is to use
Ffuncall, which embodies the Lisp function funcall. Since
the Lisp function funcall accepts an unlimited number of
arguments, in C it takes two: the number of Lisp-level arguments, and a
one-dimensional array containing their values. The first Lisp-level
argument is the Lisp function to call, and the rest are the arguments to
pass to it.
The C functions call0, call1, call2, and so on,
provide handy ways to call a Lisp function conveniently with a fixed
number of arguments. They work by calling Ffuncall.
eval.c is a very good file to look through for examples; lisp.h contains the definitions for some important macros and functions.
If you define a function which is side-effect free or pure, give it
a non-nil side-effect-free or pure property,
respectively (see 标准符号属性). See the lists defined in
‘byte-opt.el’.
This section describes the Emacs module API and how to use it as part of writing extension modules for Emacs. The module API is defined in the C programming language, therefore the description and the examples in this section assume the module is written in C. For other programming languages, you will need to use the appropriate bindings, interfaces and facilities for calling C code. Emacs C code requires a C99 or later compiler (see C Dialect), and so the code examples in this section also follow that standard.
Writing a module and integrating it into Emacs comprises the following tasks:
The following subsections describe these tasks and the API itself in more detail.
Once your module is written, compile it to produce a shared library,
according to the conventions of the underlying platform. Then place
the shared library in a directory mentioned in load-path
(see 库搜索), where Emacs will find it.
If you wish to verify the conformance of a module to the Emacs dynamic module API, invoke Emacs with the --module-assertions option. See Initial Options in The GNU Emacs Manual.
Begin your module by including the header file emacs-module.h and defining the GPL compatibility symbol:
#include <emacs-module.h> int plugin_is_GPL_compatible;
The emacs-module.h file is installed into your system’s include tree as part of the Emacs installation. Alternatively, you can find it in the Emacs source tree.
Next, write an initialization function for the module.
int emacs_module_init (struct emacs_runtime *runtime) ¶Emacs calls this function when it loads a module. If a module does
not export a function named emacs_module_init, trying to load
the module will signal an error. The initialization function should
return zero if the initialization succeeds, non-zero otherwise. In
the latter case, Emacs will signal an error, and the loading of the
module will fail. If the user presses C-g during the
initialization, Emacs ignores the return value of the initialization
function and quits (see 退出). (If needed, you can catch user
quitting inside the initialization function, see should_quit.)
The argument runtime is a pointer to a C struct that
includes 2 public fields: size, which provides the size of the
structure in bytes; and get_environment, which provides a
pointer to a function that allows the module initialization function
access to the Emacs environment object and its interfaces.
The initialization function should perform whatever initialization is required for the module. In addition, it can perform the following tasks:
A module can verify that the Emacs executable which loads the module
is compatible with the module, by comparing the size member of
the runtime structure with the value compiled into the module:
int
emacs_module_init (struct emacs_runtime *runtime)
{
if (runtime->size < sizeof (*runtime))
return 1;
}
If the size of the runtime object passed to the module is smaller than what it expects, it means the module was compiled for an Emacs version newer (later) than the one which attempts to load it, i.e. the module might be incompatible with the Emacs binary.
In addition, a module can verify the compatibility of the module
API with what the module expects. The following sample code
assumes it is part of the emacs_module_init function shown
above:
emacs_env *env = runtime->get_environment (runtime);
if (env->size < sizeof (*env))
return 2;
This calls the get_environment function using the pointer
provided in the runtime structure to retrieve a pointer to the
API’s environment, a C struct which also has a
size field holding the size of the structure in bytes.
Finally, you can write a module that will work with older versions of Emacs, by comparing the size of the environment passed by Emacs with known sizes, like this:
emacs_env *env = runtime->get_environment (runtime);
if (env->size >= sizeof (struct emacs_env_26))
emacs_version = 26; /* Emacs 26 or later. */
else if (env->size >= sizeof (struct emacs_env_25))
emacs_version = 25;
else
return 2; /* Unknown or unsupported version. */
This works because later Emacs versions always add members to the environment, never remove any members, so the size can only grow with new Emacs releases. Given the version of Emacs, the module can use only the parts of the module API that existed in that version, since those parts are identical in later versions.
emacs-module.h defines a preprocessor macro
EMACS_MAJOR_VERSION. It expands to an integer literal which is
the latest major version of Emacs supported by the header.
See 版本信息. Note that the value of
EMACS_MAJOR_VERSION is a compile-time constant and does not
represent the version of Emacs that is currently running and has
loaded your module. If you want your module to be compatible with
various versions of emacs-module.h as well as various versions
of Emacs, you can use conditional compilation based on
EMACS_MAJOR_VERSION.
We recommend that modules always perform the compatibility verification, unless they do their job entirely in the initialization function, and don’t access any Lisp objects or use any Emacs functions accessible through the environment structure.
This gives the module functions names so that Lisp code could call it by that name. We describe how to do this in Writing Module Functions below.
The main reason for writing an Emacs module is to make additional functions available to Lisp programs that load the module. This subsection describes how to write such module functions.
A module function has the following general form and signature:
emacs_value emacs_function (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) ¶The env argument provides a pointer to the API
environment, needed to access Emacs objects and functions. The
nargs argument is the required number of arguments, which can be
zero (see make_function below for more flexible specification
of the argument number), and args is a pointer to the array of
the function arguments. The argument data points to additional
data required by the function, which was arranged when
make_function (see below) was called to create an Emacs
function from emacs_function.
Module functions use the type emacs_value to communicate Lisp
objects between Emacs and the module (see Conversion Between Lisp and Module Values). The
API, described below and in the following subsections,
provides facilities for conversion between basic C data types and the
corresponding emacs_value objects.
In the module function’s body, do not attempt to access
elements of the args array beyond the index
nargs-1: memory for the args array is allocated
exactly to accommodate nargs values, and accessing beyond that
will most probably crash your module. In particular, if the value of
nargs passed to the function at run time is zero, it must not
access args at all, as no memory will have been allocated for it
in that case.
A module function always returns a value. If the function returns
normally, the Lisp code which called it will see the Lisp object
corresponding to the emacs_value value the function returned.
However, if the user typed C-g, or if the module function or its
callees signaled an error or exited nonlocally (see Nonlocal Exits in Modules), Emacs will ignore the returned value and quit or throw as
it does when Lisp code encounters the same situations.
The header emacs-module.h provides the type
emacs_function as an alias type for a function pointer to a
module function.
After writing your C code for a module function, you should make a
Lisp function object from it using the make_function function,
whose pointer is provided in the environment (recall that the pointer
to the environment is returned by get_environment). This is
normally done in the module initialization function (see module initialization function), after verifying the API
compatibility.
emacs_value make_function (emacs_env *env, ptrdiff_t min_arity, ptrdiff_t max_arity, emacs_function func, const char *docstring, void *data) ¶This returns an Emacs function created from the C function func,
whose signature is as described for emacs_function above.
The arguments
min_arity and max_arity specify the minimum and maximum
number of arguments that func can accept. The max_arity
argument can have the special value emacs_variadic_function,
which makes the function accept an unlimited number of arguments, like
the &rest keyword in Lisp (see 参数列表的特性).
The argument data is a way to arrange for arbitrary additional
data to be passed to func when it is called. Whatever pointer
is passed to make_function will be passed unaltered to
func.
The argument docstring specifies the documentation string for
the function. It should be either an ASCII string, or a
UTF-8 encoded non-ASCII string, or a NULL pointer; in
the latter case the function will have no documentation. The
documentation string can end with a line that specifies the advertised
calling convention, see 函数的文档字符串.
Since every module function must accept the pointer to the environment
as its first argument, the call to make_function could be made
from any module function, but you will normally want to do that from
the module initialization function, so that all the module functions
are known to Emacs once the module is loaded.
Finally, you should bind the Lisp function to a symbol, so that Lisp
code could call your function by name. For that, use the module
API function intern (see intern) whose pointer is
also provided in the environment that module functions can access.
Combining the above steps, code that arranges for a C function
module_func to be callable as module-func from Lisp will
look like this, as part of the module initialization function:
emacs_env *env = runtime->get_environment (runtime);
emacs_value func = env->make_function (env, min_arity, max_arity,
module_func, docstring, data);
emacs_value symbol = env->intern (env, "module-func");
emacs_value args[] = {symbol, func};
env->funcall (env, env->intern (env, "defalias"), 2, args);
This makes the symbol module-func known to Emacs by calling
env->intern, then invokes defalias from Emacs to bind
the function to that symbol. Note that it is possible to use
fset instead of defalias; the differences are described
in defalias.
Module functions including the emacs_module_init function
(see module initialization function) may only interact with Emacs
by calling environment functions from some live emacs_env
pointer while being called directly or indirectly from Emacs. In
other words, if a module function wants to call Lisp functions or
Emacs primitives, convert emacs_value objects to and from C
datatypes (see Conversion Between Lisp and Module Values), or interact with Emacs in any other
way, some call from Emacs to emacs_module_init or to a module
function must be in the call stack. Module functions may not interact
with Emacs while garbage collection is running; see Garbage Collection. They may only interact with Emacs from Lisp interpreter
threads (including the main thread) created by Emacs; see Threads.
The --module-assertions command-line option can detect some
violations of the above requirements. See Initial Options in The GNU Emacs Manual.
Using the module API, it is possible to define more complex
function and data types: inline functions, macros, etc. However, the
resulting C code will be cumbersome and hard to read. Therefore, we
recommend that you limit the module code which creates functions and
data structures to the absolute minimum, and leave the rest for a Lisp
package that will accompany your module, because doing these
additional tasks in Lisp is much easier, and will produce a much more
readable code. For example, given a module function
module-func defined as above, one way of making a macro
module-macro based on it is with the following simple Lisp
wrapper:
(defmacro module-macro (&rest args) "Documentation string for the macro." (module-func args))
The Lisp package which goes with your module could then load the
module using the load primitive (see Emacs 动态模块) when
the package is loaded into Emacs.
By default, module functions created by make_function are not
interactive. To make them interactive, you can use the following
function.
void make_interactive (emacs_env *env, emacs_value function, emacs_value spec) ¶This function, which is available since Emacs 28, makes the function
function interactive using the interactive specification
spec. Emacs interprets spec like the argument to the
interactive form. 使用 interactive, and
see interactive 的代码字符. function must be an Emacs module
function returned by make_function.
Note that there is no native module support for retrieving the
interactive specification of a module function. Use the function
interactive-form for that. 使用 interactive. It is not
possible to make a module function non-interactive once you have made
it interactive using make_interactive.
If you want to run some code when a module function object (i.e., an
object returned by make_function) is garbage-collected, you can
install a function finalizer. Function finalizers are available
since Emacs 28. For example, if you have passed some heap-allocated
structure to the data argument of make_function, you can
use the finalizer to deallocate the structure. See (libc)Basic
Allocation, and see (libc)Freeing after Malloc. The
finalizer function has the following signature:
void finalizer (void *data)
Here, data receives the value passed to data when calling
make_function. Note that the finalizer can’t interact with
Emacs in any way.
Directly after calling make_function, the newly-created
function doesn’t have a finalizer. Use set_function_finalizer
to add one, if desired.
void emacs_finalizer (void *ptr) ¶The header emacs-module.h provides the type
emacs_finalizer as a type alias for an Emacs finalizer
function.
emacs_finalizer get_function_finalizer (emacs_env *env, emacs_value arg) ¶This function, which is available since Emacs 28, returns the function
finalizer associated with the module function represented by
arg. arg must refer to a module function, that is, an
object returned by make_function. If no finalizer is
associated with the function, NULL is returned.
void set_function_finalizer (emacs_env *env, emacs_value arg, emacs_finalizer fin) ¶This function, which is available since Emacs 28, sets the function
finalizer associated with the module function represented by arg
to fin. arg must refer to a module function, that is, an
object returned by make_function. fin can either be
NULL to clear arg’s function finalizer, or a pointer to a
function to be called when the object represented by arg is
garbage-collected. At most one function finalizer can be set per
function; if arg already has a finalizer, it is replaced by
fin.
With very few exceptions, most modules need to exchange data with
Lisp programs that call them: accept arguments to module functions and
return values from module functions. For this purpose, the module
API provides the emacs_value type, which represents
Emacs Lisp objects communicated via the API; it is the
functional equivalent of the Lisp_Object type used in Emacs C
primitives (see Writing Emacs Primitives). This section describes
the parts of the module API that allow creating
emacs_value objects corresponding to basic Lisp data types, and
how to access from C data in emacs_value objects that
correspond to Lisp objects.
All of the functions described below are actually function pointers provided via the pointer to the environment which every module function accepts. Therefore, module code should call these functions through the environment pointer, like this:
emacs_env *env; /* the environment pointer */ env->some_function (arguments...);
The emacs_env pointer will usually come from the first argument
to the module function, or from the call to get_environment if
you need the environment in the module initialization function.
Most of the functions described below became available in Emacs 25, the first Emacs release that supported dynamic modules. For the few functions that became available in later Emacs releases, we mention the first Emacs version that supported them.
The following API functions extract values of various C data
types from emacs_value objects. They all raise the
wrong-type-argument error condition (see 类型谓词)
if the argument emacs_value object is not of the type expected
by the function. See Nonlocal Exits in Modules, for details of how signaling
errors works in Emacs modules, and how to catch error conditions
inside the module before they are reported to Emacs. The
API function type_of (see type_of)
can be used to obtain the type of a emacs_value object.
intmax_t extract_integer (emacs_env *env, emacs_value arg) ¶This function returns the value of a Lisp integer specified by
arg. The C data type of the return value, intmax_t, is
the widest integer data type supported by the C compiler, typically
long long. If the value of arg doesn’t fit into an
intmax_t, the function signals an error using the error symbol
overflow-error.
bool extract_big_integer (emacs_env *env, emacs_value arg, int *sign, ptrdiff_t *count, emacs_limb_t *magnitude) ¶This function, which is available since Emacs 27, extracts the
integer value of arg. The value of arg must be an
integer (fixnum or bignum). If sign is not NULL, it
stores the sign of arg (-1, 0, or +1) into *sign. The
magnitude is stored into magnitude as follows. If count
and magnitude are both non-NULL, then magnitude must
point to an array of at least *count unsigned long
elements. If magnitude is large enough to hold the magnitude of
arg, then this function writes the magnitude into the
magnitude array in little-endian form, stores the number of
array elements written into *count, and returns true.
If magnitude is not large enough, it stores the required array
size into *count, signals an error, and returns false.
If count is not NULL and magnitude is NULL,
then the function stores the required array size into *count
and returns true.
Emacs guarantees that the maximum required value of *count
never exceeds min (PTRDIFF_MAX, SIZE_MAX) / sizeof
(emacs_limb_t), so you can use malloc (*count * sizeof *magnitude)
to allocate the magnitude array without worrying about integer
overflow in the size calculation.
This is an unsigned integer type, used as the element type for the magnitude arrays for the big integer conversion functions. The type is guaranteed to have unique object representations, i.e., no padding bits.
This macro expands to a constant expression specifying the maximum
possible value for an emacs_limb_t object.
The expression is suitable for use in #if.
double extract_float (emacs_env *env, emacs_value arg) ¶This function returns the value of a Lisp float specified by
arg, as a C double value.
struct timespec extract_time (emacs_env *env, emacs_value arg) ¶This function, which is available since Emacs 27, interprets arg
as an Emacs Lisp time value and returns the corresponding struct
timespec. See Time of Day. struct timespec represents a
timestamp with nanosecond precision. It has the following members:
time_t tv_secWhole number of seconds.
long tv_nsecFractional seconds as a number of nanoseconds.
For timestamps returned by extract_time,
this is always nonnegative and less than one billion.
(Although POSIX requires the type of tv_nsec to be long,
the type is long long on some nonstandard platforms.)
See (libc)Elapsed Time.
If time has higher precision than nanoseconds, then this
function truncates it to nanosecond precision towards negative
infinity. This function signals an error if time (truncated to
nanoseconds) cannot be represented by struct timespec. For
example, if time_t is a 32-bit integer type, then a time
value of ten billion seconds would signal an error, but a time
value of 600 picoseconds would get truncated to zero.
If you need to deal with time values that are not representable by
struct timespec, or if you want higher precision, call the Lisp
function encode-time and work with its return value.
See Time Conversion.
bool copy_string_contents (emacs_env *env, emacs_value arg, char *buf, ptrdiff_t *len) ¶This function stores the UTF-8 encoded text of a Lisp string specified
by arg in the array of char pointed by buf, which
should have enough space to hold at least *len bytes,
including the terminating null byte. The argument len must not
be a NULL pointer, and, when the function is called, it should
point to a value that specifies the size of buf in bytes.
If the buffer size specified by *len is large enough to
hold the string’s text, the function stores in *len the
actual number of bytes copied to buf, including the terminating
null byte, and returns true. If the buffer is too small, the
function raises the args-out-of-range error condition, stores
the required number of bytes in *len, and returns
false. See Nonlocal Exits in Modules, for how to handle pending error
conditions.
The argument buf can be a NULL pointer, in which case the
function stores in *len the number of bytes required for
storing the contents of arg, and returns true. This is
how you can determine the size of buf needed to store a
particular string: first call copy_string_contents with
NULL as buf, then allocate enough memory to hold the
number of bytes stored by the function in *len, and call
the function again with non-NULL buf to actually perform
the text copying.
emacs_value vec_get (emacs_env *env, emacs_value vector, ptrdiff_t index) ¶This function returns the element of vector at index. The
index of the first vector element is zero. The function raises
the args-out-of-range error condition if the value of
index is invalid. To extract C data from the value the function
returns, use the other extraction functions described here, as
appropriate for the Lisp data type stored in that element of the
vector.
ptrdiff_t vec_size (emacs_env *env, emacs_value vector) ¶This function returns the number of elements in vector.
void vec_set (emacs_env *env, emacs_value vector, ptrdiff_t index, emacs_value value) ¶This function stores value in the element of vector whose
index is index. It raises the args-out-of-range error
condition if the value of index is invalid.
The following API functions create emacs_value
objects from basic C data types. They all return the created
emacs_value object.
emacs_value make_integer (emacs_env *env, intmax_t n) ¶This function takes an integer argument n and returns the
corresponding emacs_value object. It returns either a fixnum
or a bignum depending on whether the value of n is inside the
limits set by most-negative-fixnum and
most-positive-fixnum (see 整数基础).
emacs_value make_big_integer (emacs_env *env, int sign, ptrdiff_t count, const emacs_limb_t *magnitude) ¶This function, which is available since Emacs 27, takes an
arbitrary-sized integer argument and returns a corresponding
emacs_value object. The sign argument gives the sign of
the return value. If sign is nonzero, then magnitude must
point to an array of at least count elements specifying the
little-endian magnitude of the return value.
The following example uses the GNU Multiprecision Library (GMP) to
calculate the next probable prime after a given integer.
See (gmp)Top, for a general overview of GMP, and see (gmp)Integer
Import and Export for how to convert the magnitude array
to and from GMP mpz_t values.
#include <emacs-module.h>
int plugin_is_GPL_compatible;
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>
static void
memory_full (emacs_env *env)
{
static const char message[] = "Memory exhausted";
emacs_value data = env->make_string (env, message,
strlen (message));
env->non_local_exit_signal
(env, env->intern (env, "error"),
env->funcall (env, env->intern (env, "list"), 1, &data));
}
enum
{
order = -1, endian = 0, nails = 0,
limb_size = sizeof (emacs_limb_t),
max_nlimbs = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
/ limb_size)
};
static bool
extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
{
ptrdiff_t nlimbs;
bool ok = env->extract_big_integer (env, arg, NULL, &nlimbs, NULL);
if (!ok)
return false;
assert (0 < nlimbs && nlimbs <= max_nlimbs);
emacs_limb_t *magnitude = malloc (nlimbs * limb_size);
if (magnitude == NULL)
{
memory_full (env);
return false;
}
int sign;
ok = env->extract_big_integer (env, arg, &sign, &nlimbs, magnitude);
assert (ok);
mpz_import (result, nlimbs, order, limb_size, endian, nails, magnitude);
free (magnitude);
if (sign < 0)
mpz_neg (result, result);
return true;
}
static emacs_value
make_big_integer (emacs_env *env, const mpz_t value)
{
size_t nbits = mpz_sizeinbase (value, 2);
int bitsperlimb = CHAR_BIT * limb_size - nails;
size_t nlimbs = nbits / bitsperlimb + (nbits % bitsperlimb != 0);
emacs_limb_t *magnitude
= nlimbs <= max_nlimbs ? malloc (nlimbs * limb_size) : NULL;
if (magnitude == NULL)
{
memory_full (env);
return NULL;
}
size_t written;
mpz_export (magnitude, &written, order, limb_size, endian, nails, value);
assert (written == nlimbs);
assert (nlimbs <= PTRDIFF_MAX);
emacs_value result = env->make_big_integer (env, mpz_sgn (value),
nlimbs, magnitude);
free (magnitude);
return result;
}
static emacs_value
next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
void *data)
{
assert (nargs == 1);
mpz_t p;
mpz_init (p);
extract_big_integer (env, args[0], p);
mpz_nextprime (p, p);
emacs_value result = make_big_integer (env, p);
mpz_clear (p);
return result;
}
int
emacs_module_init (struct emacs_runtime *runtime)
{
emacs_env *env = runtime->get_environment (runtime);
emacs_value symbol = env->intern (env, "next-prime");
emacs_value func
= env->make_function (env, 1, 1, next_prime, NULL, NULL);
emacs_value args[] = {symbol, func};
env->funcall (env, env->intern (env, "defalias"), 2, args);
return 0;
}
emacs_value make_float (emacs_env *env, double d) ¶This function takes a double argument d and returns the
corresponding Emacs floating-point value.
emacs_value make_time (emacs_env *env, struct timespec time) ¶This function, which is available since Emacs 27, takes a struct
timespec argument time and returns the corresponding Emacs
timestamp as a pair (ticks . hz). See Time of Day. The return value represents exactly the same timestamp as
time: all input values are representable, and there is never a
loss of precision. time.tv_sec and
time.tv_nsec can be arbitrary values. In particular,
there’s no requirement that time be normalized. This means that
time.tv_nsec can be negative or larger than 999,999,999.
emacs_value make_string (emacs_env *env, const char *str, ptrdiff_t len) ¶This function creates an Emacs string from C text string pointed by
str whose length in bytes, not including the terminating null
byte, is len. The original string in str can be either an
ASCII string or a UTF-8 encoded non-ASCII string;
it can include embedded null bytes, and doesn’t have to end in a
terminating null byte at str[len]. The function
raises the overflow-error error condition if len is
negative or exceeds the maximum length of an Emacs string. If
len is zero, then str can be NULL, otherwise it
must point to valid memory. For nonzero len, make_string
returns unique mutable string objects.
emacs_value make_unibyte_string (emacs_env *env, const char *str, ptrdiff_t len) ¶This function is like make_string, but has no restrictions on
the values of the bytes in the C string, and can be used to pass
binary data to Emacs in the form of a unibyte string.
The API does not provide functions to manipulate Lisp data
structures, for example, create lists with cons and list
(see 构建 cons 单元与列表), extract list members with car and
cdr (see 访问列表元素), create vectors with vector
(see 向量相关函数), etc. For these, use intern and
funcall, described in the next subsection, to call the
corresponding Lisp functions.
Normally, emacs_value objects have a rather short lifetime: it
ends when the emacs_env pointer used for their creation goes
out of scope. Occasionally, you may need to create global
references: emacs_value objects that live as long as you
wish. Use the following two functions to manage such objects.
emacs_value make_global_ref (emacs_env *env, emacs_value value) ¶This function returns a global reference for value.
void free_global_ref (emacs_env *env, emacs_value global_value) ¶This function frees the global_value previously created by
make_global_ref. The global_value is no longer valid
after the call. Your module code should pair each call to
make_global_ref with the corresponding free_global_ref.
An alternative to keeping around C data structures that need to be
passed to module functions later is to create user pointer
objects. A user pointer, or user-ptr, object is a Lisp object
that encapsulates a C pointer and can have an associated finalizer
function, which is called when the object is garbage-collected
(see Garbage Collection). The module API provides
functions to create and access user-ptr objects. These
functions raise the wrong-type-argument error condition if they
are called on emacs_value that doesn’t represent a
user-ptr object.
emacs_value make_user_ptr (emacs_env *env, emacs_finalizer fin, void *ptr) ¶This function creates and returns a user-ptr object which wraps
the C pointer ptr. The finalizer function fin can be a
NULL pointer (meaning no finalizer), or it can be a function of
the following signature:
typedef void (*emacs_finalizer) (void *ptr);
If fin is not a NULL pointer, it will be called with the
ptr as the argument when the user-ptr object is
garbage-collected. Don’t run any expensive code in a finalizer,
because GC must finish quickly to keep Emacs responsive.
void *get_user_ptr (emacs_env *env, emacs_value arg) ¶This function extracts the C pointer from the Lisp object represented by arg.
void set_user_ptr (emacs_env *env, emacs_value arg, void *ptr) ¶This function sets the C pointer embedded in the user-ptr
object represented by arg to ptr.
emacs_finalizer get_user_finalizer (emacs_env *env, emacs_value arg) ¶This function returns the finalizer of the user-ptr object
represented by arg, or NULL if it doesn’t have a
finalizer.
void set_user_finalizer (emacs_env *env, emacs_value arg, emacs_finalizer fin) ¶This function changes the finalizer of the user-ptr object
represented by arg to be fin. If fin is a
NULL pointer, the user-ptr object will have no
finalizer.
Note that the emacs_finalizer type works for both user pointer
an module function finalizers. See Module Function Finalizers.
This subsection describes a few convenience functions provided by
the module API. Like the functions described in previous
subsections, all of them are actually function pointers, and need to
be called via the emacs_env pointer. Description of functions
that were introduced after Emacs 25 calls out the first version where
they became available.
bool eq (emacs_env *env, emacs_value a, emacs_value b) ¶This function returns true if the Lisp objects represented by
a and b are identical, false otherwise. This is
the same as the Lisp function eq (see 相等性谓词),
but avoids the need to intern the objects represented by the
arguments.
There are no API functions for other equality predicates, so
you will need to use intern and funcall, described
below, to perform more complex equality tests.
bool is_not_nil (emacs_env *env, emacs_value arg) ¶This function tests whether the Lisp object represented by arg
is non-nil; it returns true or false accordingly.
Note that you could implement an equivalent test by using
intern to get an emacs_value representing nil,
then use eq, described above, to test for equality. But using
this function is more convenient.
emacs_value type_of (emacs_env *env, emacs_value arg) ¶This function returns the type of arg as a value that represents
a symbol: string for a string, integer for an integer,
process for a process, etc. See 类型谓词. You can
use intern and eq to compare against known type symbols,
if your code needs to depend on the object type.
emacs_value intern (emacs_env *env, const char *name) ¶This function returns an interned Emacs symbol whose name is name, which should be an ASCII null-terminated string. It creates a new symbol if one does not already exist.
Together with funcall, described below, this function provides
a means for invoking any Lisp-callable Emacs function, provided that
its name is a pure ASCII string. For example, here’s how to
intern a symbol whose name name_str is non-ASCII, by
calling the more powerful Emacs intern function
(see 创建与编入符号):
emacs_value fintern = env->intern (env, "intern"); emacs_value sym_name = env->make_string (env, name_str, strlen (name_str)); emacs_value symbol = env->funcall (env, fintern, 1, &sym_name);
emacs_value funcall (emacs_env *env, emacs_value func, ptrdiff_t nargs, emacs_value *args) ¶This function calls the specified func passing it nargs
arguments from the array pointed to by args. The argument
func can be a function symbol (e.g., returned by intern
described above), a module function returned by make_function
(see Writing Module Functions), a subroutine written in C, etc. If
nargs is zero, args can be a NULL pointer.
The function returns the value that func returned.
If your module includes potentially long-running code, it is a good idea to check from time to time in that code whether the user wants to quit, e.g., by typing C-g (see 退出). The following function, which is available since Emacs 26.1, is provided for that purpose.
bool should_quit (emacs_env *env) ¶This function returns true if the user wants to quit. In that
case, we recommend that your module function aborts any on-going
processing and returns as soon as possible. In most cases, use
process_input instead.
To process input events in addition to checking whether the user wants to quit, use the following function, which is available since Emacs 27.1.
enum emacs_process_input_result process_input (emacs_env *env) ¶This function processes pending input events. It returns
emacs_process_input_quit if the user wants to quit or an error
occurred while processing signals. In that case, we recommend that
your module function aborts any on-going processing and returns as
soon as possible. If the module code may continue running,
process_input returns emacs_process_input_continue. The
return value is emacs_process_input_continue if and only if
there is no pending nonlocal exit in env. If the module
continues after calling process_input, global state such as
variable values and buffer content may have been modified in arbitrary
ways.
int open_channel (emacs_env *env, emacs_value pipe_process) ¶This function, which is available since Emacs 28, opens a channel to
an existing pipe process. pipe_process must refer to an
existing pipe process created by make-pipe-process. Pipe Processes. If successful, the return value will be a new file
descriptor that you can use to write to the pipe. Unlike all other
module functions, you can use the returned file descriptor from
arbitrary threads, even if no module environment is active. You can
use the write function to write to the file descriptor. Once
done, close the file descriptor using close. (libc)Low-Level
I/O.
Emacs Lisp supports nonlocal exits, whereby program control is
transferred from one point in a program to another remote point.
See 非局部退出. Thus, Lisp functions called by your module
might exit nonlocally by calling signal or throw, and
your module functions must handle such nonlocal exits properly. Such
handling is needed because C programs will not automatically release
resources and perform other cleanups in these cases; your module code
must itself do it. The module API provides facilities for
that, described in this subsection. They are generally available
since Emacs 25; those of them that became available in later releases
explicitly call out the first Emacs version where they became part of
the API.
When some Lisp code called by a module function signals an error or
throws, the nonlocal exit is trapped, and the pending exit and its
associated data are stored in the environment. Whenever a nonlocal
exit is pending in the environment, any module API function
called with a pointer to that environment will return immediately
without any processing (the functions non_local_exit_check,
non_local_exit_get, and non_local_exit_clear are
exceptions from this rule). If your module function then does nothing
and returns to Emacs, a pending nonlocal exit will cause Emacs to act
on it: signal an error or throw to the corresponding catch.
So the simplest “handling” of nonlocal exits in module functions is to do nothing special and let the rest of your code to run as if nothing happened. However, this can cause two classes of problems:
Therefore, we recommend that your module functions check for nonlocal exit conditions and recover from them, using the functions described below.
enum emacs_funcall_exit non_local_exit_check (emacs_env *env) ¶This function returns the kind of nonlocal exit condition stored in env. The possible values are:
enum emacs_funcall_exit non_local_exit_get (emacs_env *env, emacs_value *symbol, emacs_value *data) ¶This function returns the kind of nonlocal exit condition stored in
env, like non_local_exit_check does, but it also returns
the full information about the nonlocal exit, if any. If the return
value is emacs_funcall_exit_signal, the function stores the
error symbol in *symbol and the error data in
*data (see 如何发出错误信号). If the return value is
emacs_funcall_exit_throw, the function stores the catch
tag symbol in *symbol and the throw value in
*data. The function doesn’t store anything in memory
pointed by these arguments when the return value is
emacs_funcall_exit_return.
You should check nonlocal exit conditions where it matters: before you allocated some resource or after you allocated a resource that might need freeing, or where a failure means further processing is impossible or infeasible.
Once your module function detected that a nonlocal exit is pending, it can either return to Emacs (after performing the necessary local cleanup), or it can attempt to recover from the nonlocal exit. The following API functions will help with these tasks.
void non_local_exit_clear (emacs_env *env) ¶This function clears the pending nonlocal exit conditions and data from env. After calling it, the module API functions will work normally. Use this function if your module function can recover from nonlocal exits of the Lisp functions it calls and continue, and also before calling any of the following two functions (or any other API functions, if you want them to perform their intended processing when a nonlocal exit is pending).
void non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value) ¶This function throws to the Lisp catch symbol represented by
tag, passing it value as the value to return. Your module
function should in general return soon after calling this function.
One use of this function is when you want to re-throw a non-local exit
from one of the called API or Lisp functions.
void non_local_exit_signal (emacs_env *env, emacs_value symbol, emacs_value data) ¶This function signals the error represented by the error symbol symbol with the specified error data data. The module function should return soon after calling this function. This function could be useful, e.g., for signaling errors from module functions to Emacs.
Emacs Lisp provides a rich set of the data types. Some of them, like cons cells, integers and strings, are common to nearly all Lisp dialects. Some others, like markers and buffers, are quite special and needed to provide the basic support to write editor commands in Lisp. To implement such a variety of object types and provide an efficient way to pass objects between the subsystems of an interpreter, there is a set of C data structures and a special type to represent the pointers to all of them, which is known as tagged pointer.
In C, the tagged pointer is an object of type Lisp_Object. Any
initialized variable of such a type always holds the value of one of the
following basic data types: integer, symbol, string, cons cell, float,
or vectorlike object. Each of these data types has the
corresponding tag value. All tags are enumerated by enum Lisp_Type
and placed into a 3-bit bitfield of the Lisp_Object. The rest of the
bits is the value itself. Integers are immediate, i.e., directly
represented by those value bits, and all other objects are represented
by the C pointers to a corresponding object allocated from the heap. Width
of the Lisp_Object is platform- and configuration-dependent: usually
it’s equal to the width of an underlying platform pointer (i.e., 32-bit on
a 32-bit machine and 64-bit on a 64-bit one), but also there is a special
configuration where Lisp_Object is 64-bit but all pointers are 32-bit.
The latter trick was designed to overcome the limited range of values for
Lisp integers on a 32-bit system by using 64-bit long long type for
Lisp_Object.
The following C data structures are defined in lisp.h to represent the basic data types beyond integers:
struct Lisp_ConsCons cell, an object used to construct lists.
struct Lisp_StringString, the basic object to represent a sequence of characters.
struct Lisp_VectorArray, a fixed-size set of Lisp objects which may be accessed by an index.
struct Lisp_SymbolSymbol, the unique-named entity commonly used as an identifier.
struct Lisp_FloatFloating-point value.
These types are the first-class citizens of an internal type system.
Since the tag space is limited, all other types are the subtypes of
Lisp_Vectorlike. Vector subtypes are enumerated
by enum pvec_type, and nearly all complex objects like windows, buffers,
frames, and processes fall into this category.
Below there is a description of a few subtypes of Lisp_Vectorlike.
Buffer object represents the text to display and edit. Window is the part
of display structure which shows the buffer or is used as a container to
recursively place other windows on the same frame. (Do not confuse Emacs Lisp
window object with the window as an entity managed by the user interface
system like X; in Emacs terminology, the latter is called frame.) Finally,
process object is used to manage the subprocesses.
Two structures (see buffer.h) are used to represent buffers
in C. The buffer_text structure contains fields describing the
text of a buffer; the buffer structure holds other fields. In
the case of indirect buffers, two or more buffer structures
reference the same buffer_text structure.
Here are some of the fields in struct buffer_text:
begThe address of the buffer contents. The buffer contents is a linear C
array of char, with the gap somewhere in its midst.
gptgpt_byteThe character and byte positions of the buffer gap. See The Buffer Gap.
zz_byteThe character and byte positions of the end of the buffer text.
gap_sizeThe size of buffer’s gap. See The Buffer Gap.
modiffsave_modiffchars_modiffoverlay_modiffThese fields count the number of buffer-modification events performed
in this buffer. modiff is incremented after each
buffer-modification event, and is never otherwise changed;
save_modiff contains the value of modiff the last time
the buffer was visited or saved; chars_modiff counts only
modifications to the characters in the buffer, ignoring all other
kinds of changes (such as text properties); and overlay_modiff
counts only modifications to the buffer’s overlays.
beg_unchangedend_unchangedThe number of characters at the start and end of the text that are known to be unchanged since the last complete redisplay.
unchanged_modifiedoverlay_unchanged_modifiedThe values of modiff and overlay_modiff, respectively,
after the last complete redisplay. If their current values match
modiff or overlay_modiff, that means
beg_unchanged and end_unchanged contain no useful
information.
markersThe markers that refer to this buffer. This is actually a single marker, and successive elements in its marker chain (a linked list) are the other markers referring to this buffer text.
intervalsThe interval tree which records the text properties of this buffer.
Some of the fields of struct buffer are:
headerA header of type union vectorlike_header is common to all
vectorlike objects.
own_textA struct buffer_text structure that ordinarily holds the buffer
contents. In indirect buffers, this field is not used.
textA pointer to the buffer_text structure for this buffer. In an
ordinary buffer, this is the own_text field above. In an
indirect buffer, this is the own_text field of the base buffer.
nextA pointer to the next buffer, in the chain of all buffers, including killed buffers. This chain is used only for allocation and garbage collection, in order to collect killed buffers properly.
ptpt_byteThe character and byte positions of point in a buffer.
begvbegv_byteThe character and byte positions of the beginning of the accessible range of text in the buffer.
zvzv_byteThe character and byte positions of the end of the accessible range of text in the buffer.
base_bufferIn an indirect buffer, this points to the base buffer. In an ordinary buffer, it is null.
local_flagsThis field contains flags indicating that certain variables are local
in this buffer. Such variables are declared in the C code using
DEFVAR_PER_BUFFER, and their buffer-local bindings are stored
in fields in the buffer structure itself. (Some of these fields are
described in this table.)
modtimeThe modification time of the visited file. It is set when the file is written or read. Before writing the buffer into a file, this field is compared to the modification time of the file to see if the file has changed on disk. See Buffer Modification.
auto_save_modifiedThe time when the buffer was last auto-saved.
last_window_startThe window-start position in the buffer as of the last time the
buffer was displayed in a window.
clip_changedThis flag indicates that narrowing has changed in the buffer. See Narrowing.
prevent_redisplay_optimizations_pThis flag indicates that redisplay optimizations should not be used to display this buffer.
inhibit_buffer_hooksThis flag indicates that the buffer should not run the hooks
kill-buffer-hook, kill-buffer-query-functions
(see Killing Buffers), and buffer-list-update-hook
(see The Buffer List). It is set at buffer creation (see Creating Buffers), and avoids slowing down internal or temporary buffers, such
as those created by with-temp-buffer (see Current Buffer).
nameA Lisp string that names the buffer. It is guaranteed to be unique.
See Buffer Names. This and the following fields have their names
in the C struct definition end in a _ to indicate that they
should not be accessed directly, but via the BVAR macro, like
this:
Lisp_Object buf_name = BVAR (buffer, name);
save_lengthThe length of the file this buffer is visiting, when last read or
saved. It can have 2 special values: −1 means auto-saving was
turned off in this buffer, and −2 means don’t turn off
auto-saving if buffer text shrinks a lot. This and other fields
concerned with saving are not kept in the buffer_text structure
because indirect buffers are never saved.
directoryThe directory for expanding relative file names. This is the value of
the buffer-local variable default-directory (see 文件名展开相关函数).
filenameThe name of the file visited in this buffer, or nil. This is
the value of the buffer-local variable buffer-file-name
(see Buffer File Name).
undo_listbacked_upauto_save_file_nameauto_save_file_formatread_onlyfile_formatfile_truenameinvisibility_specdisplay_countdisplay_timeThese fields store the values of Lisp variables that are automatically
buffer-local (see 缓冲区局部变量), whose corresponding
variable names have the additional prefix buffer- and have
underscores replaced with dashes. For instance, undo_list
stores the value of buffer-undo-list.
markThe mark for the buffer. The mark is a marker, hence it is also
included on the list markers. See The Mark.
local_var_alistThe association list describing the buffer-local variable bindings of this buffer, not including the built-in buffer-local bindings that have special slots in the buffer object. (Those slots are omitted from this table.) See 缓冲区局部变量.
major_modeSymbol naming the major mode of this buffer, e.g., lisp-mode.
mode_namePretty name of the major mode, e.g., "Lisp".
keymapabbrev_tablesyntax_tablecategory_tabledisplay_tableThese fields store the buffer’s local keymap (see 按键映射), abbrev table (see Abbrev Tables), syntax table (see Syntax Tables), category table (see Categories), and display table (see Display Tables).
downcase_tableupcase_tablecase_canon_tableThese fields store the conversion tables for converting text to lower case, upper case, and for canonicalizing text for case-fold search. See 大小写转换表.
minor_modesAn alist of the minor modes of this buffer.
pt_markerbegv_markerzv_markerThese fields are only used in an indirect buffer, or in a buffer that
is the base of an indirect buffer. Each holds a marker that records
pt, begv, and zv respectively, for this buffer
when the buffer is not current.
mode_line_formatheader_line_formattab_widthfill_columnleft_marginauto_fill_functiontruncate_linesword_wrapctl_arrowbidi_display_reorderingbidi_paragraph_directionselective_displayselective_display_ellipsesoverwrite_modeabbrev_modemark_activeenable_multibyte_charactersbuffer_file_coding_systemcache_long_line_scanspoint_before_scrollleft_fringe_widthright_fringe_widthfringes_outside_marginsscroll_bar_widthindicate_empty_linesindicate_buffer_boundariesfringe_indicator_alistfringe_cursor_alistscroll_up_aggressivelyscroll_down_aggressivelycursor_typecursor_in_non_selected_windowsThese fields store the values of Lisp variables that are automatically
buffer-local (see 缓冲区局部变量), whose corresponding
variable names have underscores replaced with dashes. For instance,
mode_line_format stores the value of mode-line-format.
overlaysThe interval tree containing this buffer’s overlays.
last_selected_windowThis is the last window that was selected with this buffer in it, or nil
if that window no longer displays this buffer.
The fields of a window (for a complete list, see the definition of
struct window in window.h) include:
frameThe frame that this window is on, as a Lisp object.
miniNon-zero if this window is a minibuffer window, a window showing the minibuffer or the echo area.
pseudo_window_p ¶Non-zero if this window is a pseudo window. A pseudo window is either a window used to display the menu bar or the tool bar (when Emacs uses toolkits that don’t display their own menu bar and tool bar) or the tab bar or a window showing a tooltip on a tooltip frame. Pseudo windows are in general not accessible from Lisp code.
parentInternally, Emacs arranges windows in a tree; each group of siblings
has a parent window whose area includes all the siblings. This field
points to the window’s parent in that tree, as a Lisp object. For the
root window of the tree and a minibuffer window this is always
nil.
Parent windows do not display buffers, and play little role in display except to shape their child windows. Emacs Lisp programs cannot directly manipulate parent windows; they operate on the windows at the leaves of the tree, which actually display buffers.
contentsFor a leaf window and windows showing a tooltip, this is the buffer,
as a Lisp object, that the window is displaying. For an internal
(“parent”) window, this is its first child window. For a pseudo
window showing a menu or tool bar this is nil. It is also
nil for a window that has been deleted.
nextprevThe next and previous sibling of this window as Lisp objects.
next is nil if the window is the right-most or
bottom-most in its group; prev is nil if it is the
left-most or top-most in its group. Whether the sibling is left/right
or up/down is determined by the horizontal field of the
sibling’s parent: if it’s non-zero, the siblings are arranged
horizontally.
As a special case, next of a frame’s root window points to the
frame’s minibuffer window, provided this is not a minibuffer-only or
minibuffer-less frame. On such frames prev of the minibuffer
window points to that frame’s root window. In any other case, the
root window’s next and the minibuffer window’s (if present)
prev fields are nil.
left_colThe left-hand edge of the window, measured in columns, relative to the leftmost column (column 0) of the window’s native frame.
top_lineThe top edge of the window, measured in lines, relative to the topmost line (line 0) of the window’s native frame.
pixel_leftpixel_topThe left-hand and top edges of this window, measured in pixels, relative to the top-left corner (0, 0) of the window’s native frame.
total_colstotal_linesThe total width and height of the window, measured in columns and lines respectively. The values include scroll bars and fringes, dividers and/or the separator line on the right of the window (if any).
pixel_width;pixel_height;The total width and height of the window measured in pixels.
startA marker pointing to the position in the buffer that is the first character (in the logical order, see Bidirectional Display) displayed in the window.
pointm ¶This is the value of point in the current buffer when this window is selected; when it is not selected, it retains its previous value.
old_pointmThe value of pointm at the last redisplay time.
force_startIf this flag is non-nil, it says that the window has been
scrolled explicitly by the Lisp program, and the value of the
window’s start was set for redisplay to honor. This affects
what the next redisplay does if point is off the screen: instead of
scrolling the window to show the text around point, it moves point to
a location that is on the screen.
optional_new_startThis is similar to force_start, but the next redisplay will
only obey it if point stays visible.
start_at_line_begNon-nil means current value of start was the beginning of a line
when it was chosen.
use_timeThis is the last time that the window was selected. The function
get-lru-window uses this field.
sequence_numberA unique number assigned to this window when it was created.
last_modifiedThe modiff field of the window’s buffer, as of the last time
a redisplay completed in this window.
last_overlay_modifiedThe overlay_modiff field of the window’s buffer, as of the last
time a redisplay completed in this window.
last_pointThe buffer’s value of point, as of the last time a redisplay completed in this window.
last_had_starA non-zero value means the window’s buffer was modified when the window was last updated.
vertical_scroll_bar_typehorizontal_scroll_bar_typeThe types of this window’s vertical and horizontal scroll bars.
scroll_bar_widthscroll_bar_heightThe width of this window’s vertical scroll bar and the height of this window’s horizontal scroll bar, in pixels.
left_margin_colsright_margin_colsThe widths of the left and right margins in this window. A value of zero means no margin.
left_fringe_widthright_fringe_widthThe pixel widths of the left and right fringes in this window. A value of −1 means use the values of the frame.
fringes_outside_marginsA non-zero value means the fringes outside the display margins; othersize they are between the margin and the text.
window_end_posThis is computed as z minus the buffer position of the last glyph
in the current matrix of the window. The value is only valid if
window_end_valid is non-zero.
window_end_byteposThe byte position corresponding to window_end_pos.
window_end_vposThe window-relative vertical position of the line containing
window_end_pos.
window_end_validThis field is set to a non-zero value if window_end_pos and
window_end_vpos are truly valid. This is zero if nontrivial
redisplay is preempted, since in that case the display that
window_end_pos was computed for did not get onto the screen.
cursorA structure describing where the cursor is in this window.
last_cursor_vposThe window-relative vertical position of the line showing the cursor as of the last redisplay that finished.
phys_cursorA structure describing where the cursor of this window physically is.
phys_cursor_typephys_cursor_heightphys_cursor_widthThe type, height, and width of the cursor that was last displayed on this window.
phys_cursor_on_pThis field is non-zero if the cursor is physically on.
cursor_off_pNon-zero means the cursor in this window is logically off. This is used for blinking the cursor.
last_cursor_off_pThis field contains the value of cursor_off_p as of the time of
the last redisplay.
must_be_updated_pThis is set to 1 during redisplay when this window must be updated.
hscrollThis is the number of columns that the display in the window is scrolled horizontally to the left. Normally, this is 0. When only the current line is hscrolled, this describes how much the current line is scrolled.
min_hscrollMinimum value of hscroll, set by the user via
set-window-hscroll (see Horizontal Scrolling). When only
the current line is hscrolled, this describes the horizontal scrolling
of lines other than the current one.
vscrollVertical scroll amount, in pixels. Normally, this is 0.
dedicatedNon-nil if this window is dedicated to its buffer.
combination_limitThis window’s combination limit, meaningful only for a parent window.
If this is t, then it is not allowed to delete this window and
recombine its child windows with other siblings of this window.
window_parametersThe alist of this window’s parameters.
display_tableThe window’s display table, or nil if none is specified for it.
update_mode_lineNon-zero means this window’s mode line needs to be updated.
mode_line_heightheader_line_heightThe height in pixels of the mode line and the header line, or −1 if not known.
base_line_numberThe line number of a certain position in the buffer, or zero. This is used for displaying the line number of point in the mode line.
base_line_posThe position in the buffer for which the line number is known, or zero meaning none is known. If it is −1, don’t display the line number as long as the window shows that buffer.
column_number_displayedThe column number currently displayed in this window’s mode line, or −1 if column numbers are not being displayed.
current_matrixdesired_matrixGlyph matrices describing the current and desired display of this window.
The fields of a process (for a complete list, see the definition of
struct Lisp_Process in process.h) include:
nameA Lisp string, the name of the process.
commandA list containing the command arguments that were used to start this
process. For a network or serial process, it is nil if the
process is running or t if the process is stopped.
filterA Lisp function used to accept output from the process.
sentinelA Lisp function called whenever the state of the process changes.
bufferThe associated buffer of the process.
pidAn integer, the operating system’s process ID. Pseudo-processes such as network or serial connections use a value of 0.
childpA flag, t if this is really a child process. For a network or
serial connection, it is a plist based on the arguments to
make-network-process or make-serial-process.
markA marker indicating the position of the end of the last output from this process inserted into the buffer. This is often but not always the end of the buffer.
kill_without_queryIf this is non-zero, killing Emacs while this process is still running does not ask for confirmation about killing the process.
raw_statusThe raw process status, as returned by the wait system call.
statusThe process status, as process-status should return it. This
is a Lisp symbol, a cons cell, or a list.
tickupdate_tickIf these two fields are not equal, a change in the status of the process needs to be reported, either by running the sentinel or by inserting a message in the process buffer.
pty_flagNon-zero if communication with the subprocess uses a pty; zero if it uses a pipe.
infdThe file descriptor for input from the process.
outfdThe file descriptor for output to the process.
tty_nameThe name of the terminal that the subprocess is using,
or nil if it is using pipes.
decode_coding_systemCoding-system for decoding the input from this process.
decoding_bufA working buffer for decoding.
decoding_carryoverSize of carryover in decoding.
encode_coding_systemCoding-system for encoding the output to this process.
encoding_bufA working buffer for encoding.
inherit_coding_system_flagFlag to set coding-system of the process buffer from the
coding system used to decode process output.
typeSymbol indicating the type of process: real, network,
serial.
Here are some guidelines for use of integer types in the Emacs C source code. These guidelines sometimes give competing advice; common sense is advised.
int len = strlen
(s); unless the length of s is required for other reasons to
fit in int range.
size_t instead of ptrdiff_t, or uintptr_t instead
of intptr_t).
int for Emacs character codes, in the range 0 .. 0x3FFFFF.
More generally, prefer int for integers known to be in
int range, e.g., screen column counts.
ptrdiff_t for sizes, i.e., for integers bounded by the
maximum size of any individual C object or by the maximum number of
elements in any C array. This is part of Emacs’s general preference
for signed types. Using ptrdiff_t limits objects to
PTRDIFF_MAX bytes, but larger objects would cause trouble
anyway since they would break pointer subtraction, so this does not
impose an arbitrary limit.
ssize_t except when communicating to low-level APIs that
have ssize_t-related limitations. Although it’s equivalent to
ptrdiff_t on typical platforms, ssize_t is occasionally
narrower, so using it for size-related calculations could overflow.
Also, ptrdiff_t is more ubiquitous and better-standardized, has
standard printf formats, and is the basis for Emacs’s internal
size-overflow checking. When using ssize_t, please note that
POSIX requires support only for values in the range −1 ..
SSIZE_MAX.
intptr_t for internal representations of pointers, or
for integers bounded only by the number of objects that can exist at
any given time or by the total number of bytes that can be allocated.
However, prefer uintptr_t to represent pointer arithmetic that
could cross page boundaries. For example, on a machine with a 32-bit
address space an array could cross the 0x7fffffff/0x80000000 boundary,
which would cause an integer overflow when adding 1 to
(intptr_t) 0x7fffffff.
EMACS_INT for representing values
converted to or from Emacs Lisp fixnums, as fixnum arithmetic is based
on EMACS_INT.
off_t, time_t). Do not assume that a system type is
signed, unless this assumption is known to be safe. For example,
although off_t is always signed, time_t need not be.
intmax_t for representing values that might be any
signed integer value.
A printf-family function can print such a value
via a format like "%"PRIdMAX.
bool, false and true for booleans.
Using bool can make programs easier to read and a bit faster than
using int. Although it is also OK to use int, 0
and 1, this older style is gradually being phased out. When
using bool, respect the limitations of the replacement
implementation of bool. In particular,
boolean bitfields should be of type
bool_bf, not bool, so that they work correctly even when
compiling Objective C with standard GCC.
unsigned int or signed int to
int, as int is less portable: it might be signed, and
might not be. Single-bit bit fields should be unsigned int or
bool_bf so that their values are 0 or 1.
Here is a list of the more important error symbols in standard Emacs, grouped by concept. The list includes each symbol’s message and a cross reference to a description of how the error can occur.
Each error symbol has a set of parent error conditions that is a
list of symbols. Normally this list includes the error symbol itself
and the symbol error. Occasionally it includes additional
symbols, which are intermediate classifications, narrower than
error but broader than a single error symbol. For example, all
the errors in accessing files have the condition file-error. If
we do not say here that a certain error symbol has additional error
conditions, that means it has none.
As a special exception, the error symbols quit and
minibuffer-quit don’t have the condition error, because
quitting is not considered an error.
Most of these error symbols are defined in C (mainly data.c),
but some are defined in Lisp. For example, the file userlock.el
defines the file-locked and file-supersession errors.
Several of the specialized Lisp libraries distributed with Emacs
define their own error symbols. We do not attempt to list of all
those here.
See 错误, for an explanation of how errors are generated and handled.
errorThe message is ‘error’. See 错误.
quitThe message is ‘Quit’. See 退出.
minibuffer-quitThe message is ‘Quit’. This is a subcategory of quit.
See 退出.
args-out-of-rangeThe message is ‘Args out of range’. This happens when trying to access an element beyond the range of a sequence, buffer, or other container-like object. See 序列、数组与向量, and see Text.
arith-errorThe message is ‘Arithmetic error’. This occurs when trying to perform integer division by zero. See 数值转换, and see 算术运算.
beginning-of-bufferThe message is ‘Beginning of buffer’. See Motion by Characters.
buffer-read-onlyThe message is ‘Buffer is read-only’. See Read-Only Buffers.
circular-listThe message is ‘List contains a loop’. This happens when a circular structure is encountered. See 循环对象的读取语法.
cl-assertion-failedThe message is ‘Assertion failed’. This happens when the
cl-assert macro fails a test. See Assertions in Common Lisp
Extensions.
coding-system-errorThe message is ‘Invalid coding system’. See Coding Systems in Lisp.
cyclic-function-indirectionThe message is ‘Symbol's chain of function indirections contains a loop’. See 符号函数间接引用.
cyclic-variable-indirectionThe message is ‘Symbol's chain of variable indirections contains a loop’. See 变量别名.
dbus-errorThe message is ‘D-Bus error’. See Errors and Events in D-Bus integration in Emacs.
end-of-bufferThe message is ‘End of buffer’. See Motion by Characters.
end-of-fileThe message is ‘End of file during parsing’. Note that this is
not a subcategory of file-error, because it pertains to the
Lisp reader, not to file I/O. See 输入函数.
file-already-existsThis is a subcategory of file-error. See 写入文件.
permission-deniedThis is a subcategory of file-error, which occurs when the OS
doesn’t allow Emacs to access a file or a directory for some reason.
file-date-errorThis is a subcategory of file-error. It occurs when
copy-file tries and fails to set the last-modification time of
the output file. See 修改文件名与属性.
file-errorWe do not list the error-strings of this error and its subcategories,
because the error message is normally constructed from the data items
alone when the error condition file-error is present. Thus,
the error-strings are not very relevant. However, these error symbols
do have error-message properties, and if no data is provided,
the error-message property is used. See 文件.
file-missingThis is a subcategory of file-error. It occurs when an
operation attempts to act on a file that is missing. See 修改文件名与属性.
compression-errorThis is a subcategory of file-error, which results from
problems handling a compressed file. See 程序的加载方式.
file-lockedThis is a subcategory of file-error. See 文件锁.
file-supersessionThis is a subcategory of file-error. See Buffer Modification Time.
file-notify-errorThis is a subcategory of file-error. It happens, when a file
could not be watched for changes. See Notifications on File Changes.
remote-file-errorThis is a subcategory of file-error, which results from
problems in accessing a remote file. See Remote Files in The
GNU Emacs Manual. Often, this error appears when timers, process
filters, process sentinels or special events in general try to access
a remote file, and collide with another remote file operation. In
general it is a good idea to write a bug report.
See Bugs in The GNU Emacs Manual.
ftp-errorThis is a subcategory of remote-file-error, which results from
problems in accessing a remote file using ftp. See Remote Files in The GNU Emacs Manual.
invalid-functionThe message is ‘Invalid function’. See 符号函数间接引用.
invalid-read-syntaxThe message is usually ‘Invalid read syntax’. See 打印表示与读入语法. This error can also be raised by commands like
eval-expression when there’s text following an expression. In
that case, the message is ‘Trailing garbage following expression’.
invalid-regexpThe message is ‘Invalid regexp’. See Regular Expressions.
mark-inactiveThe message is ‘The mark is not active now’. See The Mark.
no-catchThe message is ‘No catch for tag’. See 显式非局部退出:catch 和 throw.
range-errorThe message is Arithmetic range error.
overflow-errorThe message is ‘Arithmetic overflow error’. This is a subcategory
of range-error.
This can happen with integers exceeding the integer-width limit.
See 整数基础.
scan-errorThe message is ‘Scan error’. This happens when certain syntax-parsing functions find invalid syntax or mismatched parentheses. Conventionally raised with three argument: a human-readable error message, the start of the obstacle that cannot be moved over, and the end of the obstacle. See Moving over Balanced Expressions, and see Parsing Expressions.
search-failedThe message is ‘Search failed’. See Searching and Matching.
setting-constantThe message is ‘Attempt to set a constant symbol’. This happens
when attempting to assign values to nil, t,
most-positive-fixnum, most-negative-fixnum, and keyword
symbols. It also happens when attempting to assign values to
enable-multibyte-characters and some other symbols whose direct
assignment is not allowed for some reason. See 永不改变的变量.
text-read-onlyThe message is ‘Text is read-only’. This is a subcategory of
buffer-read-only. See Properties with Special Meanings.
undefined-colorThe message is ‘Undefined color’. See Color Names.
user-errorThe message is the empty string. See 如何发出错误信号.
user-search-failedThis is like ‘search-failed’, but doesn’t trigger the debugger, like ‘user-error’. See 如何发出错误信号, and see Searching and Matching. This is used for searching in Info files, see Search Text in Info.
void-functionThe message is ‘Symbol's function definition is void’. See 访问函数单元内容.
void-variableThe message is ‘Symbol's value as variable is void’. See 访问变量值.
wrong-number-of-argumentsThe message is ‘Wrong number of arguments’. See 参数列表的特性.
wrong-type-argumentThe message is ‘Wrong type argument’. See 类型谓词.
unknown-image-typeThe message is ‘Cannot determine image type’. See Images.
inhibited-interactionThe message is ‘User interaction while inhibited’. This error is
signaled when inhibit-interaction is non-nil and a user
interaction function (like read-from-minibuffer) is called.
In this section we list some of the more general keymaps. Many of these exist when Emacs is first started, but some are loaded only when the respective feature is accessed.
There are many other, more specialized, maps than these; in particular those associated with major and minor modes. The minibuffer uses several keymaps (see 执行补全的小缓冲命令). For more details on keymaps, see 按键映射.
2C-mode-mapA sparse keymap for subcommands of the prefix C-x 6.
See Two-Column Editing in The GNU Emacs Manual.
abbrev-map ¶A sparse keymap for subcommands of the prefix C-x a.
See Defining Abbrevs in The GNU Emacs Manual.
button-buffer-mapA sparse keymap useful for buffers containing buttons.
You may want to use this as a parent keymap. See Buttons.
button-mapA sparse keymap used by buttons.
ctl-x-4-mapA sparse keymap for subcommands of the prefix C-x 4.
ctl-x-5-mapA sparse keymap for subcommands of the prefix C-x 5.
ctl-x-mapA full keymap for C-x commands.
ctl-x-r-map ¶A sparse keymap for subcommands of the prefix C-x r.
See Registers in The GNU Emacs Manual.
esc-mapA full keymap for ESC (or Meta) commands.
function-key-mapThe parent keymap of all local-function-key-map (q.v.) instances.
global-mapThe full keymap containing default global key bindings.
Modes should not modify the Global map.
goto-mapA sparse keymap used for the M-g prefix key.
help-mapA sparse keymap for the keys following the help character C-h.
See 帮助函数.
Helper-help-mapA full keymap used by the help utility package.
It has the same keymap in its value cell and in its function cell.
input-decode-mapThe keymap for translating keypad and function keys.
If there are none, then it contains an empty sparse keymap.
See 事件序列翻译键盘映射.
key-translation-mapA keymap for translating keys. This one overrides ordinary key
bindings, unlike local-function-key-map. See 事件序列翻译键盘映射.
kmacro-keymap ¶A sparse keymap for keys that follows the C-x C-k prefix search.
See Keyboard Macros in The GNU Emacs Manual.
local-function-key-mapThe keymap for translating key sequences to preferred alternatives.
If there are none, then it contains an empty sparse keymap.
See 事件序列翻译键盘映射.
menu-bar-file-menu ¶menu-bar-edit-menumenu-bar-options-menuglobal-buffers-menu-mapmenu-bar-tools-menumenu-bar-help-menuThese keymaps display the main, top-level menus in the menu bar.
Some of them contain sub-menus. For example, the Edit menu contains
menu-bar-search-menu, etc. See 菜单栏.
minibuffer-inactive-mode-map ¶A full keymap used in the minibuffer when it is not active.
See Editing in the Minibuffer in The GNU Emacs Manual.
mode-line-coding-system-map ¶mode-line-input-method-mapmode-line-column-line-number-mode-mapThese keymaps control various areas of the mode line.
See 模式行格式.
mode-specific-mapThe keymap for characters following C-c. Note, this is in the
global map. This map is not actually mode-specific: its name was chosen
to be informative in C-h b (display-bindings),
where it describes the main use of the C-c prefix key.
mouse-appearance-menu-map ¶A sparse keymap used for the S-mouse-1 key.
mule-keymapThe global keymap used for the C-x RET prefix key.
narrow-map ¶A sparse keymap for subcommands of the prefix C-x n.
prog-mode-map ¶The keymap used by Prog mode.
See 基础主模式.
query-replace-mapmulti-query-replace-mapA sparse keymap used for responses in query-replace and related
commands; also for y-or-n-p and map-y-or-n-p. The functions
that use this map do not support prefix keys; they look up one event at a
time. multi-query-replace-map extends query-replace-map
for multi-buffer replacements. See query-replace-map.
search-mapA sparse keymap that provides global bindings for search-related commands.
special-mode-map ¶The keymap used by Special mode.
See 基础主模式.
tab-prefix-mapThe global keymap used for the C-x t prefix key for tab-bar related commands.
See Tab Bars in The GNU Emacs Manual.
tab-bar-map ¶The keymap defining the contents of the tab bar.
See Tab Bars in The GNU Emacs Manual.
tool-bar-mapThe keymap defining the contents of the tool bar.
See 工具栏.
universal-argument-map ¶A sparse keymap used while processing C-u.
See 前缀命令参数.
vc-prefix-mapThe global keymap used for the C-x v prefix key.
x-alternatives-map ¶A sparse keymap used to map certain keys under graphical frames.
The function x-setup-function-keys uses this.
The following is a list of some hook variables that let you provide functions to be called from within Emacs on suitable occasions.
Most of these variables have names ending with ‘-hook’. They are
normal hooks, run by means of run-hooks. The value of such
a hook is a list of functions; the functions are called with no
arguments and their values are completely ignored. The recommended way
to put a new function on such a hook is to call add-hook.
See 钩子, for more information about using hooks.
The variables whose names end in ‘-functions’ are usually abnormal hooks (some old code may also use the deprecated ‘-hooks’ suffix). Their values are lists of functions, but these functions are called in a special way: they are either passed arguments, or their return values are used in some way. The variables whose names end in ‘-function’ have single functions as their values.
This is not an exhaustive list, it only covers the more general hooks.
For example, every major mode defines a hook named
‘modename-mode-hook’. The major mode command runs this
normal hook with run-mode-hooks as the very last thing it does.
See 模式钩子. Most minor modes have mode hooks too.
A special feature allows you to specify expressions to evaluate if and when a file is loaded (see 加载相关钩子). That feature is not exactly a hook, but does a similar job.
activate-mark-hookdeactivate-mark-hookSee The Mark.
after-change-functionsbefore-change-functionsfirst-change-hookSee Change Hooks.
after-change-major-mode-hookchange-major-mode-after-body-hookSee 模式钩子.
after-init-hookbefore-init-hookemacs-startup-hookwindow-setup-hookSee The Init File.
after-insert-file-functionswrite-region-annotate-functionswrite-region-post-annotation-functionSee 文件格式转换.
after-make-frame-functionsbefore-make-frame-hookserver-after-make-frame-hookSee Creating Frames.
after-save-hookbefore-save-hookwrite-contents-functionswrite-file-functionsSee 保存缓冲区.
after-setting-font-hook ¶Hook run after a frame’s font changes.
auto-save-hookSee 自动保存.
before-hack-local-variables-hookhack-local-variables-hookSee 文件局部变量.
buffer-access-fontify-functionsbuffer-list-update-hook ¶Hook run when the buffer list changes (see The Buffer List).
buffer-quit-function ¶Function to call to quit the current buffer.
change-major-mode-hookSee 创建与删除缓冲区局部绑定.
comint-password-functionThis abnormal hook permits a derived mode to supply a password for the underlying command interpreter without prompting the user.
command-line-functionsdelayed-warnings-hook ¶The command loop runs this soon after post-command-hook (q.v.).
focus-in-hook ¶focus-out-hookSee Input Focus.
delete-frame-functionsafter-delete-frame-functionsSee Deleting Frames.
delete-terminal-functionsSee Multiple Terminals.
pop-up-frame-functionsplit-window-preferred-functionecho-area-clear-hookfind-file-hookfind-file-not-found-functionsSee 访问文件的函数.
font-lock-extend-after-change-region-functionSee 缓冲区修改后需要高亮的区域.
font-lock-extend-region-functionsSee 多行字体锁定结构.
font-lock-fontify-buffer-functionfont-lock-fontify-region-functionfont-lock-mark-block-functionfont-lock-unfontify-buffer-functionfont-lock-unfontify-region-functionSee 字体锁定其他变量.
fontification-functionsframe-auto-hide-functionSee Quitting Windows.
quit-window-hookSee Quitting Windows.
kill-buffer-hookkill-buffer-query-functionsSee Killing Buffers.
kill-emacs-hookkill-emacs-query-functionsSee Killing Emacs.
menu-bar-update-hookSee 菜单栏.
minibuffer-setup-hookminibuffer-exit-hookSee Minibuffer 杂项.
mouse-leave-buffer-hook ¶Hook run when the user mouse-clicks in a window.
mouse-position-functionSee Mouse Position.
prefix-command-echo-keystrokes-functions ¶An abnormal hook run by prefix commands (such as C-u) which
should return a string describing the current prefix state. For
example, C-u produces ‘C-u-’ and ‘C-u 1 2 3-’. Each
hook function is called with no arguments and should return a string
describing the current prefix state, or nil if there’s no
prefix state. See 前缀命令参数.
prefix-command-preserve-state-hook ¶Hook run when a prefix command needs to preserve the prefix by passing the current prefix command state to the next command. For example, C-u needs to pass the state to the next command when the user types C-u - or follows C-u with a digit.
pre-redisplay-functionsHook run in each window just before redisplaying it. See Forcing Redisplay.
post-command-hookpre-command-hookSee 命令循环概述.
post-gc-hookSee Garbage Collection.
post-self-insert-hookSee 按键映射与次要模式.
suspend-hooksuspend-resume-hooksuspend-tty-functionsresume-tty-functionsSee Suspending Emacs.
syntax-begin-functionsyntax-propertize-extend-region-functionssyntax-propertize-functionfont-lock-syntactic-face-functionSee 语法字体锁定. See Syntax Properties.
temp-buffer-setup-hooktemp-buffer-show-functiontemp-buffer-show-hookSee Temporary Displays.
tty-setup-hookwindow-configuration-change-hookwindow-scroll-functionswindow-size-change-functions| Jump to: | -
,
;
:
?
.
'
"
(
)
[
]
@
*
/
\
&
#
%
`
^
+
<
=
>
|
$
0
1
2
3
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 当 站 间 阻 |
|---|
| Jump to: | -
,
;
:
?
.
'
"
(
)
[
]
@
*
/
\
&
#
%
`
^
+
<
=
>
|
$
0
1
2
3
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 当 站 间 阻 |
|---|
你还可能见到 ‘#^^’,用于表示子字符表
不过,不同的函数对象之间,一般无法保证其相等性。
这是 Common Lisp、C 等语言对常量规定的行为,这与 JavaScript、Python 等语言不同 —— 后者要求解释器在程序试图修改不可变对象时必须抛出错误。理想情况下,Emacs Lisp 解释器未来会向后者方向演进。
有关排序规则及其区域(locale)依赖关系的更多信息,请参见The Unicode Collation Algorithm。部分标准 C 库(例如 GNU C 库,又称 glibc)实现了 Unicode 排序算法的大部分内容,并使用配套的区域数据 ——通用区域数据仓库(Common Locale Data Repository,简称 CLDR)。
有时也被称作 true list真列表,但本文档中一般不使用这一叫法。
没有严格等价的方法向列表尾部添加元素。可使用 (append listname (list newelt)),复制 listname 并在尾部添加 newelt,生成全新列表;或使用 (nconc listname (list newelt)),遍历 listname 的所有 CDR,替换末尾的 nil,直接修改 listname。对比之下,用 cons 向列表头部添加元素时,既不复制也不修改原列表。
这里 “key(键)” 的用法与 “key sequence(键序列)” 一词无关;它指用于在表中查找条目的值。在本场景下,表就是关联列表(alist),而关联列表中的各个关联项就是条目。
有时也被称作 S 表达式(S-expression) 或 sexp,但本手册中一般不使用这一术语。
这里对 “环境(environment)” 的定义特意不包含所有可能影响程序运行结果的数据。
确切地说,在默认的动态作用域规则下,值单元始终保存变量的当前值;但在词法作用域规则下则并非如此。详情请参阅 See Scoping 变量绑定的作用域规则。
存在一些例外;例如,词法绑定也可以从 Lisp 调试器中访问。
受 DOS 文件系统的限制,Emacs 的 MS-DOS 版本会改用 _dir-locals.el。
这仅在使用 lexical-binding 的代码中生效。
该概念与 柯里化(currying) 相关但并不等同:柯里化会对接收多个参数的函数进行转换,使其可作为一系列函数的链式调用执行,每个函数仅接收单个参数。
若 func 可接收的参数数量无上限,那么这个新函数也会接收无数量上限的参数;这种情况下,apply-partially 不会减少新函数可接收的参数数量。
注意:与内置的 1+ 函数不同,这个自定义版本可以接收任意数量的参数。
有些元素实际提供两个参数。
按键按下是拖拽的对立操作。
对于不使用工具集的 菜单(例如文本终端上的菜单),该标题是必需的。
在为 Cygwin 环境编译的
Windows 版 Emacs 中,可以使用函数
cygwin-convert-file-name-to-windows 与
cygwin-convert-file-name-from-windows
在两种文件名语法之间转换。
Emacs 遵循 GNU 惯例,使用术语文件名(file name) 而非路径名(pathname)。我们仅将路径(path) 用于搜索路径,即目录名列表。
On PGTK frames, setting
the values fullheight and fullwidth has no effect.
On Haiku, child frames are only visible when a parent frame is active, owing to a limitation of the Haiku windowing system. Owing to the same limitation, child frames are only guaranteed to appear above their top-level parent; that is to say, the top-most frame in the hierarchy, which does not have a parent frame.
An RFC, an acronym for Request for Comments, is a numbered Internet informational document describing a standard. RFCs are usually written by technical experts acting on their own initiative, and are traditionally written in a pragmatic, experience-driven manner.
This internal representation is based on one of the encodings defined by the Unicode Standard, called UTF-8, for representing any Unicode codepoint, but Emacs extends UTF-8 to represent the additional codepoints it uses for raw 8-bit bytes and characters not unified with Unicode.
The Unicode specification writes these tag names inside ‘<..>’ brackets, but the tag names in Emacs do not include the brackets; e.g., Unicode specifies ‘<small>’ where Emacs uses ‘small’.
It could be written much simpler with non-greedy operators (how?), but that would make the example less interesting.
Note that regexp-opt does not
guarantee that its result is absolutely the most efficient form
possible. A hand-tuned regular expression can sometimes be slightly
more efficient, but is almost never worth the effort.
On other systems, Emacs uses a Lisp emulation of
ls; see 目录内容.
For backward compatibility, you can also use a string to specify a face name; that is equivalent to a Lisp symbol with the same name.
In this context, the term font has nothing to do with Font Lock (see Font Lock Mode).
On MS-Windows, this requires w32-use-native-image-API to be set
non-nil.
In typography an em is a distance equivalent to the height of the type. For example when using 12 point type 1 em is equal to 12 points. Its use ensures distances and type remain proportional.
For more information about icon naming convention see Icon Naming Specification
The benefits of a Common Lisp-style package system are considered not to outweigh the costs.
We do use these occasionally, but try not to overdo it.