Emacs包定制和自动加载

3

我正在为一个提供了几个全局模式无关命令的包添加自定义支持。由于我不想在用户通过按键绑定显式调用命令之前加载该包,但我希望允许用户在安装包后立即进行自定义,因此我尝试使用以下代码:

;;;###autoload
(defcustom foo-bar nil 
 "bar setting for for"
 :type boolean)

;;;###autoload
(defun foo-command-1 () ...)

安装完包后,我可以调用foo-command-1。我还可以使用customize-variable 来设置和保存foo-bar。但是,当我重新启动Emacs时,foo-bar的值被重置为默认值,而且Emacs会抱怨该值在customize之外被更改。
据我所知,这是因为Emacs为defcustom放入autoloads文件的代码假定它将在Emacs在init.el中调用custom-set-variables之前运行。然而,在自动加载包之后运行初始化文件的情况下,这种情况并不成立。
这是否是已知的问题?为了解决这个问题,我用以下内容替换了以上内容:
;;;###autoload
(unless (fboundp 'foo-command-1)
 (defcustom foo-bar nil 
  "bar setting for for"
  :type boolean))

;;;###autoload
(defun foo-command-1 () ...)

将整个 defcustom 定义复制到 autoloads 中,并防止在真正加载包时第二次运行它。这样可以有效地保存选项并恢复设置。但我想知道为什么 defcustom###autoload 不能自动完成正确的操作。

2个回答

2
是的,你所做的是实现你想要的方式。如果你想自动加载一个defcustom并且关心它相对于其他代码的评估时间,那么你需要以某种方式控制这个时间。你选择的方式是合理的。
用户的初始化文件可以在用户选择的任何时候加载custom-file。如果没有使用custom-file,仍然不能确定由Customize管理的初始化文件代码部分将在何时相对于可能依赖它设置值的其他部分进行评估。

1
作为一般规则,您不希望自动加载变量。 是的,这是一个已知的问题,并且没有真正好的解决方案(我能想到的每个解决方案都有自己的一套错误/不良行为),这就是为什么我只能说“请不要自动加载变量”。 即使在它恰好做你想要的事情的情况下,根据我的经验,这也是不可取的。 它只有太多的怪癖和边角用例。

这更像是一条评论而不是答案。你提到了存在未命名的问题,却没有描述任何一个。仅仅给出做或不做某事的指导,而没有解释为什么,最多只能算是一条评论。 - Drew
你能举一个与问题中代码示例相关的错误行为的例子吗?在我的有限测试中,我还没有找到一个。 - Igor Bukanov
@IgorBukanov:对于这种特殊情况,我想到的一件事是,自动加载的代码副本被移出了其上下文,因此它不会以相同的方式继承“implicit :group”。 - Stefan
这只是使用显式:group的一个参数,这在任何情况下都是有意义的(包括对于“这个特定情况”),尤其是当前面的defcustom中存在多个:group时。此外,如果您没有明确提供:group,字节编译器会发出警告。而且,:group继承的“特性”甚至没有记录在文档中。据我所知,您反对自动加载的defcustoms早于:group“继承”功能。 - Drew
@Drew:是的,一般来说有很多更多的问题。我只是回答了在这个特定用例中指出问题的请求。如果你想要更多的问题,无论是一般的还是具体的,我当然可以找到更多。例如,对于这个特定的情况,其他问题包括“unless”测试很丑陋,它人为地将变量与函数的名称和存在联系起来,并且M-C-x不能正确地将变量重置为其默认值。 - Stefan

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