【发布时间】:2011-10-17 07:03:42
【问题描述】:
我想在正确安装特定软件包的同时自定义环境。如何检查elisp中是否安装了某些包? 像这样?:
(if (require 'ecb)
(progn (setq ....))
(message "ECB not installed!"))
【问题讨论】:
我想在正确安装特定软件包的同时自定义环境。如何检查elisp中是否安装了某些包? 像这样?:
(if (require 'ecb)
(progn (setq ....))
(message "ECB not installed!"))
【问题讨论】:
tripleee 的回答是错误处理的一个方便示例,但在这种情况下是不必要的。
(when (require 'some-library nil 'noerror)
do-things)
'noerror 可以是任何非零值,但当然,这种方式更具描述性。我也经常看到:noerror 也被使用,但我不知道在符号上使用关键字参数是否有什么特别的优势(cmets,有人吗?我很想知道)。
require 是
C source code中的内置函数。(需要 FEATURE &optional FILENAME NOERROR)
如果未加载功能 FEATURE,请从 FILENAME 加载它。
如果 FEATURE 不是列表features的成员,则该功能
未加载;所以加载文件 FILENAME。
如果省略 FILENAME,则使用 FEATURE 的 printname 作为文件名,
并且load将尝试按顺序加载后缀.elc或.el的此名称。不带后缀的名称将不被使用。
有关后缀的完整列表,请参阅get-load-suffixes。
如果可选的第三个参数 NOERROR 不为零,
如果找不到文件,则返回 nil 而不是发出错误信号。
通常返回值为 FEATURE。
加载 FILENAME 开始和结束时的正常消息被抑制。
【讨论】:
'noerror,所以任何非零值都可以工作。我自己一直在使用t。
AUCTeX,因为不能要求AUCTeX。您需要将package-installed-p 用于AUCTeX
auctex 确实有点不寻常。看起来你可以在加载auctex 之后测试tex-site。例如(load "auctex" :noerror) (when (require 'tex-site nil :noerror) ...)
如果失败,(require) 将抛出错误。这应该就是你所需要的。
如果您只想在 ECB 可用时配置其行为,请首先考虑向ecb-hook 添加内容——这是有条件地配置 Emacs 包的常规方法。
如果没有可用的钩子,或者出于某种原因您想手动滚动它,请尝试类似
(eval-after-load 'ecb '(setq ecb-be-more-like-better-yes-p t))
如果您真的想手动滚动,可以从失败的require 中捕获错误,如下所示:
(condition-case nil
(progn
(require 'ecb)
(setq ecb-be-more-like-better-yes-p t) )
(file-error (message "ECB not available; not configuring") ))
请注意,condition-case 会从progn 中捕获任何file-error,因此您要确保不要在其中执行任何其他文件操作。最终,您可能只想将 require 放入 condition-case 并将其用作原始 if 表单的条件,但这已经失控了......
(if (condition-case nil (require 'ecb) (error nil))
(setq ecb-be-more-like-better-yes-p t)
(message "ECB not available; not configuring") )
【讨论】:
eval-after-load 似乎没有加载包。于是我改成了下面的答案:(when (...))
eval-after-load 的目的是指定在加载指定包时执行的延迟操作。当您为不涉及加载 ecb 的任务启动 Emacs 时,这对于避免不必要的设置很有用(批量字节编译是一个常年的例子)。
为什么不使用“featurep”?
(featurep FEATURE &optional SUBFEATURE)
如果 Emacs 中存在 FEATURE,则返回 t。
(if (featurep 'ecb)
(message "ECB is there!"))
【讨论】:
对于想知道如何检查是否安装了 package.el 包的人,请使用package-installed-p。
【讨论】:
这个问题晚了四年,但是...这里有一个简单的宏可以为你做这件事。
(defmacro when-feature-loaded (feature &rest body)
"Executes BODY if and only if FEATURE is loaded."
(declare (indent defun))
`(when (featurep ,module)
@,body))
例如:
(when-feature-loaded 'foo
(message "foo is loaded!"))
这是另一个带有“else”案例的版本,以防您也需要处理。
(defmacro if-feature-loaded (module then-form else-form)
"Executes THEN-FORM if and only if MODULE is already loaded, otherwise executes ELSE-FORM."
(declare (indent 2))
`(if (featurep ,module)
,then-form
,else-form))
【讨论】:
最简单的答案是使用require 和eval-after-load,如其他答案所述。
但这并不总是很方便,例如在一个模式挂钩调用的函数中,它想要激活另一个次要模式,但前提是安装了它的包。在这种情况下,featurep 是相关的。
Emacs 包越来越多地使用自动加载来缩短启动时间。如果您使用require 测试包是否存在,那么您将承担加载文件的成本。如果使用 ELPA/MELPA/Marmalade 包(自版本 24 起默认可用),那么许多包可能在尚未加载的状态下可用,但带有自动加载功能的包 foo 将提供 foo-autoloads 功能。我编写了一个函数,该函数可用于测试包是否可用,是否已加载或设置为自动加载。
(defun autofeaturep (feature)
"For a feature symbol 'foo, return a result equivalent to:
(or (featurep 'foo-autoloads) (featurep 'foo))
Does not support subfeatures."
(catch 'result
(let ((feature-name (symbol-name feature)))
(unless (string-match "-autoloads$" feature-name)
(let ((feature-autoloads (intern-soft (concat feature-name "-autoloads"))))
(when (and feature-autoloads (featurep feature-autoloads))
(throw 'result t))))
(featurep feature))))
【讨论】: