混淆了Emacs自定义系统

51

有几个类似的设置函数:

  1. set和setq
  2. set-default
  3. defcustom
  4. custom-set-value
  5. custom-set-variables
  6. customize-set-value
  7. customize-set-variable

那么,这些函数有什么区别呢?

如果我想要将我的偏好设置用于插件,以下情况使用哪种设置函数更好:

  1. 如果一个变量是由defcustom设置的,则哪个设置函数更好?
  2. 如果一个变量是由defvar设置的,则怎么做?
4个回答

66

对于您的问题的简短回答是:

  • 对于由defvar定义的变量,请使用setqsetq-default

  • 对于由defcustom定义的变量,请使用setqsetq-defaultCustomize机制。

下面是详细的答案。

你将会用到以下函数:

  • set是设置变量值的主要函数。

  • setq是另一个版本,它自动引用其第一个参数。这很有用,因为几乎所有情况下都需要引用第一个参数。

  • 有些变量不能全局设置。每次设置变量时,只有当前缓冲区被设置。如果你想模拟全局设置这个变量,可以使用set-defaultsetq-default

包编写者使用的函数有:

  • defvar允许包编写者定义一个变量并提供一些文档说明。这个函数不是必需的,但它使用户的生活更容易。

  • defcustom是在defvar基础上构建的。它告诉emacs它是一个变量,并允许开发者创建一个custom接口来设置值。开发者可以说,像“这个变量只能包含'foo'或'bar'的值”之类的话。

设置变量有两种方式:

  1. 如果使用了defvar,则用户只能通过在其.emacs中使用set函数(或变体)来设置值。

  2. 如果使用了defcustom,可以通过set(参见1)或使用Customize来设置值。当使用自定义机制时,Emacs将生成一些代码,并将其放在custom-set-variables中。用户不应该使用此函数。


1
如果包的作者没有使用defvar而只是使用setq,那么你只能在加载包后覆盖该值。但是,如果用户可以更改该值,则不应在包中仅使用setq而不使用defvar。如果使用编写正确的包,则使用setqcustom没有区别。 - Nicolas Dudebout
2
这个陈述是不正确的。这就是我给出解释的原因。你可以随时使用 setq 设置任何你想要的东西,它不会报错。如果使用了 defvar,那么当包被加载时,emacs 将意识到一个值已经被设置,并且不会采用 defvar 中给定的默认值。 - Nicolas Dudebout
如果您使用包的内容来设置值(例如使用包提供的函数),则在加载包之前可以看到的错误会发生。如果您只使用“正常”的值(如字符串)设置值,则不会遇到问题。 - Nicolas Dudebout
嗯,看来我对它的工作原理有些误解,谢谢。 - jtahlborn
1
过去困扰我的另一个错误是尝试向列表中添加元素。如果包定义了标准列表,而我想要添加到该列表中,我需要等待包被加载(使用eval-after-load)才能添加到列表中,或者复制整个列表并添加我的元素(这就是自定义所做的)。 - Nicolas Dudebout
1
不要忘记,setq 可以分配给多个变量,而 set 只能分配给一个变量。 - gbrener

11
它们基本上都是达到同一目的的方式,虽然有一些重要差异。最好的了解方法是阅读Emacs和Elisp手册(参见C-h i)。但是,就直觉而言,以下是一些重要差异:
  • set 是“低级”变量赋值。
  • (setq foo bar)(set (quote foo) bar) 的简写。
  • (set-default foo bar) 的意思是“除非在当前缓冲区中有更明确范围的foo定义,否则使用值bar”,并适用于所有缓冲区。
  • defcustom 用于标记变量,表示用户可以安全地通过customize功能修改它。
  • custom-set-valuecustomize-set-value是指向同一个函数的两个名称。它们是使用customize系统的便捷方法。
  • custom-set-variablescustomize-set-variables用于激活某些通过customize定制的变量集合,如果我没记错的话。

通常建议使用M-x customize来更改设置。您可以自由地使用setsetq设置在您的.emacs文件中定义的内容,但如果您后来通过customize更改它,定制系统会警告您。

defcustom通常只由编写用于分发的软件包的人使用,我认为除了在内部文件中使用customize-set-*之外,没有人使用过它们。不管这些东西是否标记为与customize一起使用,setq在人们的初始化文件中都很常见,用于设置自己喜欢的内容。

我对所有这些并没有全面的了解,希望其他人能提供更多的信息,但我认为这是一个相当不错的概述 :P


把以下与编程有关的内容从英语翻译成中文。只返回翻译后的文本,不要进行解释。 - hbin

7
  1. setsetq 是用于分配任何类型变量的最低级别原语。
  2. set-defaultsetq-default 是emacs扩展,与缓冲区本地变量一起使用,允许设置新缓冲区使用的默认值。 3-7. 所有“自定义”内容是后来添加的,旨在支持用作用户首选项的变量的用户界面管理。
  3. defcustom 类似于 defvar,但允许您指定选项层次结构中的位置,以及数据类型信息,以便UI可以将值显示为菜单,或自动将用户输入转换为适当的类型。
  4. 我认为没有 custom-set-value 函数。
  5. custom-set-variables 由自定义UI在保存所有用户选项时使用。它列出了用户已从其默认值更改的所有变量。 6-7. custom-set-valuecustom-set-variable 由自定义UI用于提示用户当前和默认值的选项变量,并将它们分配。通常情况下你不会自己调用它们。

4
作为补充,由于引入了词法绑定,这些命令之间的差异已经增加,但如果您只想自定义一些变量,则这些差异实际上并不重要。 def... 构造声明全局变量。 set... 函数设置变量,无论是全局还是局部变量。当 x 既不是局部变量(当前函数的形式参数或由 let 表单或类似方式声明)也没有被 def... 表单定义时,您编写 (setq x 0) 将会导致字节编译器显示警告。
Warning: assignment to free variable `x'

defvardefcustomdefconst 声明的变量是动态绑定的。也就是说,当你有一个结构时:

(let ((lisp-indent-offset 2))
  (pp (some-function)))

函数some-function将看到全局变量lisp-indent-offset的更改。

当一个变量没有被动态绑定时,就像...

(let ((my-local-var 1))
  (some-function))

如果my-local-var没有全局值,则some-function将无法看到已分配的值,因为它是按词法作用域作用的。

另一方面,动态作用域变量不会被捕获到词法闭包中。

更多细节请参见http://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html


3
为了清晰起见,除非在文件中明确启用词法绑定,否则所有变量都将是动态绑定的,无论它们如何被定义和设置。 - phils

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接