求助一个elisp函数,为特定mode-hook增加自动补全后端

(defun maple/add-company-backend (backend)
  "Add BACKEND to `company-backends'."
  (after-load 'company
    (set (make-local-variable 'company-backends)
         (append (list backend) company-backends))
    (setq company-backends (mapcar #'company-mode/backend-with-yas company-backends))))

(defun maple/add-to-company-backend (backend &optional hook)
  "Add BACKEND to `company-backends'."
  (if hook
      (add-hook hook (lambda () (maple/add-company-backend backend)))
    (maple/add-company-backend backend)))

(maple/add-to-company-backend '(company-web-html) 'web-mode-hook)

打开一个 html 文件结果提示

File mode specification error: (void-variable backend)

这是什么问题?

company-web-html?

是我的失误,源代码的确是 company-web-html,与这个无关

看起来需要开启 lexical-binding,或者构造 lambda 的时候执行 backend

;; Error
((lambda (x) (lambda () x)) 123)
     => (lambda nil x)

;; Backquote
((lambda (x) `(lambda () ,x)) 123)
     => (lambda nil 123)

;; Lexical Binding
(setq lexical-binding t)
     => t
((lambda (x) (lambda () x)) 123)
     => (closure ((x . 123) t) nil x)

  • after-load 是什么?你想用的是 eval-after-load / with-eval-after-load
  • (set (make-local-variable 'foo) 123) 也可以换成 (setq-local foo 123)
  • 在 List 头添加一个元素,也可以用 push

问题已解决 参考问题

(defun maple/add-to-company-backend (backend &optional hook)
  "Add BACKEND to `company-backends'."
  (lexical-let ((backend backend)
                (hook hook))
    (if hook
        (add-hook hook (lambda () (maple/add-company-backend backend)))
      (lambda () (maple/add-company-backend backend)))))

谢谢大家的回复

  • after-load参考自 purcell
 (if (fboundp 'with-eval-after-load)
     (defalias 'after-load 'with-eval-after-load)
   (defmacro after-load (feature &rest body)
     "After FEATURE is loaded, evaluate BODY."
     (declare (indent defun))
     `(eval-after-load ,feature
        '(progn ,@body))))
  • (setq-local foo 123)确实可以

现在可以直接用 (info “(elisp) Lexical Binding”) 了,在 Emacs 24.1(发布于 2012 年)中引入。

哦, with-eval-after-load 在 Emacs 24.4(发布于 2014 年)中引入的。