[elisp新手历险] 在function里add-hook ... lambda ...

我需要给不同的major mode设置不同的company-backends,自然想到用个函数wrap一下,省略掉

(add-hook 'web-mode-hook (lambda ()
(setq-local company-backends (append '(company-web-html company-css) company-backends))))

这里的lambda setq-local append部分。


一开始写出来是这样的:

(defun jester/set-company-backends-for-mode (mode backends)
    "append `BACKENDS' to the head of default `company-backends',
use the result for `MODE'\'s local `company-backends'."
    (add-hook (intern (format "%s\-hook" mode))
              (lambda () (setq-local company-backends (append backends company-backends)))))

结果一直显示backends是个void variable。想了很久,明明这是个普通的function啊,backends作为参数不是会被eval吗,哪里出了问题。


终于灵光乍现:lambda里面的内容不会被eval!怎么办呢,要eval它再构造lambda,只能用macro了,试着写了下,测试下来是对的:

(defmacro jester/set-company-backends-for-mode (mode backends)
    "append `BACKENDS' to the head of default `company-backends',
use the result for `MODE'\'s local `company-backends'."
    `(add-hook (intern (format "%s\-hook" ,mode))
              (lambda () (setq-local company-backends (append ,backends company-backends)))))
1 个赞
(setq lexical-binding t)

开启lexical binding就可以用函数啦

我是把这个过程直接写在各个mode-hook里……

不过现在其实就设一个company-backends也没什么关系,因为backends会自行判断要不要加载

2 个赞

变量作用域的问题,跟这个帖子一样:如何定义函数来嵌入after-make-frame-functions

真的!随便看了下company-css里有

(or (derived-mode-p 'css-mode)
    (and (derived-mode-p 'web-mode)
         (string= (web-mode-language-at-pos) "css")))

还有lexical-binding下lambda自动成为closure