解决Yasnippet和Company的TAB冲突问题

当我使用company候选的时候,TAB键同时是yasnippet的yas-expandyas-next-field,也是company 的company-complete-common。经常在我选择yas-expand时便直接给我弹出候选了。尤其是启动tabnine后的强大的fuzzy search,必须C-g关闭候选再输入TAB进行yas-expand,非常烦。

我在论坛找了找,最接近理想的答案是这个,但这个的问题是直接把company-active-map的TAB改成yas-expand了,我还是希望保留company-complete-common的,于是自己写了一个function:

(defun smarter-yas-expand-next-field-complete ()
    "Try to `yas-expand' and `yas-next-field' at current cursor position.

If failed try to complete the common part with `company-complete-common'"
    (interactive)
    (if yas-minor-mode
        (let ((old-point (point))
              (old-tick (buffer-chars-modified-tick)))
          (yas-expand)
          (when (and (eq old-point (point))
                     (eq old-tick (buffer-chars-modified-tick)))
            (ignore-errors (yas-next-field))
            (when (and (eq old-point (point))
                       (eq old-tick (buffer-chars-modified-tick)))
              (company-complete-common))))
      (company-complete-common)))

这样,在出现company候选时,TAB键优先判断是不是snippet的缩写,然后判断可不可以snippet-next-field,最后才通过company-complete-common尝试补全。

绑定:

  (with-eval-after-load 'company
    (define-key company-active-map [tab] #'yas-expand)
    (define-key company-active-map (kbd "TAB") #'yas-expand))

use-package:

(use-package company
  ...
  :bind
  (:map company-active-map
        ([tab] . smarter-yas-expand-next-field-complete)
        ("TAB" . smarter-yas-expand-next-field-complete))...)

大家可参考:

2赞

太麻烦了 还得按个tab


(setq company-backends
   '((:separate company-yasnippet company-capf) )

Grouped backends
================

An element of `company-backends' can also be a list of backends.  The
completions from backends in such groups are merged, but only from those
backends which return the same `prefix'.

If a backend command takes a candidate as an argument (e.g. `meta'), the
call is dispatched to the backend the candidate came from.  In other
cases (except for `duplicates' and `sorted'), the first non-nil value among
all the backends is returned.

The group can also contain keywords.  Currently, `:with' and `:separate'
keywords are defined.  If the group contains keyword `:with', the backends
listed after this keyword are ignored for the purpose of the `prefix'
command.  If the group contains keyword `:separate', the candidates that
come from different backends are sorted separately in the combined list.

别人是在yasnippet field里启动company,想用tab在company移动候选项时。产生冲突要改键,你这个是什么玩意

我并不准备用company补全yas。

?我们说的有区别吗

回复你那楼楼上

1赞

哦 理解错了 没怎么用过yasnippet里的$1

如果是想在yas展开的过程中company

我觉得绑定空格键挺好的 如果必须要输入点什么 空格可以代表不输入 也就不会冲突了

spacemacs使用空格说明是有好处的

如果你用company补全yas 还会有这个问题吗?

空格就代表空格自己就行了呀

emmm 我回头看看company-yasnippet怎么样

我现在不用的一个原因是我已经tabnine+lsp一起用了,company显示的东西已经够多了。。。

我曾经用过TAB同时处理三种(yas-expand, auto-complete, indent),后来不用了,你参考下: (你用时把auto-complete替换为company-complete-common就好了, auto-completion是company类似的老包。)

;;
;; Integration of "indent" + /auto-complete/ + /yas/
;;
(defun check-expansion ()
  (save-excursion
    (if (looking-at "\\_>") t
      (backward-char 1)
      (if (looking-at "\\.") t
        (backward-char 1)
        (if (looking-at "->") t nil)))))

(defun do-yas-expand ()
  (let ((yas/fallback-behavior 'return-nil))
    (yas-expand)))

(defun tab-indent-or-complete ()
  (interactive)
  (if (minibufferp)
      (minibuffer-complete)
    (if (or (not yas/minor-mode)
            (null (do-yas-expand)))
        (if (check-expansion)
            (auto-complete)
          (indent-for-tab-command)))))

(if (display-graphic-p)
    (global-set-key (kbd "<tab>") 'tab-indent-or-complete)
  ;; <tab> is not available in terminal, "TAB" is used instead
  (global-set-key (kbd "TAB") 'tab-indent-or-complete))

正好是我需要的。 只是好奇,后来为什么不用了。