如何结合 company 与 vterm?

eshell-mode 有这个包可以补全各种 shell 命令以及显示 man 文档

还没仔细研究过 company,有没有人尝试过结合 vterm 来实现类似的效果?

关键还是要看 vterm 能不能返回补全信息。

eshell-mode 和 shell-mode 都是基于 cmint 实现的补全,跟 run-python 一样,开箱就可以用了,就是默认没有好看的前端。

尝试写了一个,现在只能手动触发补全,不造怎么自动触发。

  (setq company-shell-modes '(sh-mode shell-mode eshell-mode vterm-mode))

  (defun company-vterm-callback (str)
    (if (eq major-mode 'vterm-mode)
        (vterm-send-string (substring str (length vterm-company-prefix)) t))
    (setq-local vterm-company-prefix nil))

  (defun company-shell! (command &optional arg &rest ignored)
    "Company mode backend for binaries found on the $PATH."
    (interactive (list 'interactive))
    (cl-case command
      (interactive (company-begin-backend 'company-shell!))
      (prefix      (company-shell--prefix company-shell-modes))
      (sorted      t)
      (duplicates  nil)
      (ignore-case nil)
      (no-cache    nil)
      (annotation  (get-text-property 0 'origin arg))
      (doc-buffer  (company-shell--doc-buffer arg))
      (meta        (company-shell--meta-string arg))
      (candidates  (progn
                     (setq-local vterm-company-prefix arg)
                     (cl-remove-if-not
                      (lambda (candidate) (string-prefix-p arg candidate))
                      (company-shell--fetch-candidates))))
      (post-completion (company-vterm-callback arg))))
  (advice-add 'company-shell :override #'company-shell!)

  (defun company-shell-env! (command &optional arg &rest ignored)
    "Company backend for environment variables."
    (interactive (list 'interactive))
    (cl-case command
      (interactive (company-begin-backend 'company-shell-env!))
      (prefix      (company-shell--prefix company-shell-modes))
      (sorted      t)
      (duplicates  nil)
      (ignore-case nil)
      (no-cache    nil)
      (annotation  "Environment Variable")
      (doc-buffer  nil)
      (meta        nil)
      (candidates  (progn
                     (setq-local vterm-company-prefix arg)
                     (cl-remove-if-not
                      (lambda (candidate) (string-prefix-p arg candidate))
                      (company-shell--fetch-env-candidates))))))
  (advice-add 'company-shell-env :override #'company-shell-env!)

  (defun company--should-complete! ()
    (and (eq company-idle-delay 'now)
         (or (eq major-mode 'vterm-mode)
             (not (or buffer-read-only
                      overriding-local-map)))
         ;; Check if in the middle of entering a key combination.
         (or (equal (this-command-keys-vector) [])
             (not (keymapp (key-binding (this-command-keys-vector)))))
         (not (and transient-mark-mode mark-active))))
  (advice-add 'company--should-complete :override #'company--should-complete!)

我用 helm&company&corfu 都试了一下,手动补全都没有问题。

company 和 corfu 都需要解除 *Vterm* 只读状态。

company 和 corfu 无法自动补全跟 vterm 的按键响应机制有关。

vterm-completion-company

初步实现了自动触发补全。

1 个赞

:+1:t2:等你完成了可以在这分享一下么 :star_struck:

好吧。

其实我不怎么用 vterm :joy:

不知有没有可能直接透过 vterm 进程实时拿到补全项,否则只能像 company-shell 那样事先 cache 一份命令/函数列表。

GitHub - CeleritasCelery/emacs-native-shell-complete: Completion in shell buffers using native mechanisms 为shell-mode写的company后端,目前我在用。主页上还有博客链接,讨论了一些技术。对vterm也许有借鉴作用。

1 个赞