spacemacs中使用company-yasnippets的正确姿势是什么?

环境是macOS Catalina + emacs 27.1 + 最新的develop

yasnippet是可以正常使用的,但不想费心去记keyword,希望company自动展示可选项

按照auto-completion layer的文档, 我在init.el里配置dotspacemacs/layers加上

(auto-completion :variables
                      spacemacs-default-company-backends '(company-files  company-capf)
                      auto-completion-enable-snippets-in-popup t)

并且在user-config打开了(global-company-mode), 理论上任何mode下C-h v company-backends的结果都应该是下面吧?

((company-files . #1=(:with company-yasnippet))
 (company-capf . #1#))

然而在go-mode下结果却是

(company-capf
 (company-go . #1=(:with company-yasnippet))
 (company-files . #1#)
 (company-capf . #1#))

看了下 go layer的代码,直接有对company进行配置,另外发现lsp-mode也会影响company,甚至一度产生bug(我的lsp是lsp-mode-20210307.1909,应该不是这个bug)。

似乎推荐直接用(global-company-mode) ?所以正确的使用姿势是什么?给每个mode加上hook (push '(company-capf :with company-yasnippet) company-backends)吗?

求鱼之外还想求渔技,有什么办法追踪有哪些函数影响了某个变量吗?比如这里的company-backends

另外发现在py mode 下是

(company-bbdb company-semantic company-cmake company-capf company-clang company-files
              (company-dabbrev-code company-gtags company-etags company-keywords)
              company-oddmuse company-dabbrev)

这个貌似是 lsp 加上去的,我这样强行去掉的:

  (add-hook 'lsp-completion-mode-hook
            (lambda ()
              (when (eq (car company-backends) 'company-capf)
                (setq company-backends (cdr company-backends)))))

spacemacs 有一套自己设定 backends 的机制,在我转成自己配置前也没弄懂😂,不确定下面像 centaur 这样行不行:

(with-no-warnings
    (with-eval-after-load 'yasnippet
      (defun company-backend-with-yas (backend)
        "Add `yasnippet' to company backend."
        (if (and (listp backend) (member 'company-yasnippet backend))
            backend
          (append (if (consp backend) backend (list backend))
                  '(:with company-yasnippet))))

      (defun company-enable-yas (&rest _)
        "Enable `yasnippet' in `company'."
        (setq company-backends
              (mapcar #'company-backend-with-yas company-backends)))

      (company-enable-yas)

      (defun my-company-yasnippet-disable-inline (fun command &optional arg &rest _ignore)
        "Enable yasnippet but disable it inline."
        (if (eq command 'prefix)
            (when-let ((prefix (funcall fun 'prefix)))
              (unless (memq (char-before (- (point) (length prefix))) '(?. ?> ?\())
                prefix))
          (funcall fun command arg)))

      (advice-add #'company-yasnippet :around #'my-company-yasnippet-disable-inline)))

有道理,我试试加个lsp-completion-mode的hook

是的,就是这点让我十分脑壳疼

查了下lsp-mode的代码,(setq lsp-completion-provider :none)能让lsp不去改company的配置,当然这就必须搭配global-company食用了。

然后python-mode似乎是因为python layer里没有company相关配置

But it is not recommended to do so, you should instead open an issue to ask for auto-completion support for the major-modes where it is missing.

1 个赞
(setq lsp-completion-provider :none)
(add-hook 'go-mode-hook 'lsp-deferred)
(add-hook 'go-mode-hook (lambda ()
    (setq-local company-backends '((company-yasnippet :separate company-capf)))
    (company-mode +1)))

希望yasnippet放在前面不会太影响,不满意自己调整顺序。

  • 首先直接搜索spacemacs的代码
  • 再搜company或lsp的代码

(setq lsp-completion-enable nil)可以更彻底地让lsp不捣鼓company设置。

这样的话貌似就没有capf了

试了一下发现确实是这样,看了下代码,lsp会跑一句(add-hook 'completion-at-point-functions #'lsp-completion-at-point nil t)

我是主要用tabnine所以让lsp别帮我改backends。