如何让 lsp-mode 根据文件后缀或其它策略选取服务

不想用那个难用的 vue-mode, 我想用 web-mode 来触发 vue-language-server, 但是 web-mode 已经被绑定到了 html 上, 这就很尴尬. 看了半天只能基于 major-mode 来匹配, 能有别的方式么? (手动艾特大佬 @MaskRay )

我设想的是

(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-vue--ls-command)
                  :major-modes '(vue-mode)
                  :file-extensions '(vue) ;; 后缀名
                  ;; 或者别的什么判断条件, 甚至传一个函数, true 的时候就启动对应的服务
                  :priority -1
                  :ignore-messages '("readFile .*? requested by Vue but content not available")
                  :server-id 'vls))

Here it is workaround of the issue. As a side note, you may bind multiple language servers to web-mode and lsp-mode will select the one with highest priority:

(add-hook 'web-mode-hook
          (lambda ()
            (when (equal "XXX" (file-name-extension buffer-file-name))
              (let ((major-mode 'vue-mode))
                (lsp)))))
3 个赞

我觉得yyoncho兄用google翻译理解我们的网络用语,要有心理阴影了。

I think it’s hard for yyoncho to understand our language (with a lot of memes) by using google translation

I try do this, I can see vls start successed, but lsp-mode and lsp-ui doesn’t work. I can’t see any information.
我试了你这种方式, 能看到 vls 服务启动了, 但是 lsp-mode 没反应, lsp-ui 什么提示也没有

It works, it doesn’t work when I put “(when …)” in use-package :config.

@yyoncho Here’s my workaround, I defined a function lsp-register-major-mode to add mode to client:

;;; init-web.el --- Init web with lsp -*- lexical-binding: t; -*-

(require 'web)
(require 'lsp)
(require 'lsp-clients)

(defmacro lsp-register-major-mode (client mode)
  "Registers major MODE to CLIENT.

\(fn 'example-ls 'example-mode)"
  (gv-letplace (getter setter) `(lsp--client-major-modes (gethash ,client lsp-clients))
    `(unless (memq ,mode ,getter)
       (funcall ,setter (push ,mode ,getter)))))

(define-derived-mode web-jsx-mode web-mode "WebJSX"
  "Major mode for editing Web & JSX templates.\\{web-jsx-map}"
  (setq web-mode-content-type "jsx"))

(define-derived-mode web-tsx-mode web-mode "WebTSX"
  "Major mode for editing Web & TSX templates.\\{web-tsx-map}"
  (setq web-mode-content-type "jsx"))

(define-derived-mode web-vue-mode web-mode "WebVUE"
  "Major mode for editing Web & VUE templates.\\{web-vue-map}")

(add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-jsx-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-tsx-mode))
(add-to-list 'auto-mode-alist '("\\.vue\\'" . web-vue-mode))

(lsp-register-major-mode 'ts-ls 'web-jsx-mode)
(lsp-register-major-mode 'ts-ls 'web-tsx-mode)
(lsp-register-major-mode 'vls 'web-vue-mode)

(provide 'init-web)

;;; init-web.el ends here

@BlindingDark 这是我的配置(原本是分散在不同文件,现在把它们凑一起)。虽然我没写过 Vue,但是试过一些例子代码没问题。

之所以定义新的 mode,是为了方便扩展,但是又避免影响其它需要使用原始 web-mode 的情况。

2 个赞

I will try to extend lsp-mode to provide a way to make this work out of the box. In the future, if you hit such “awkwardness” when using lsp-mode feel free to go ahead and file an issue. Two of the possible solutions:

  1. Allow specifying file extensions as in @BlindingDark example
  2. Allow generic match function like:
(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-vue--ls-command)
                  :major-modes '(vue-mode)
                  :activate-on (lambda (file-name project-root) ...)))

2 个赞

Is there a convenient way to edit the blacklist, or a clearer hint when a path is in blacklist?

I once mistakenly added a path to the blacklist, and then I opened the file under this path and got a hint: “XXX not in project”.

After debugging the source code, I found the problem.

This functionality is missing. Having a better message will be an improvement. Also, I am planning to add function which will be like company-diag which will provide information about which servers are available, which mode could be handled by them + information about the current buffer.

1 个赞

@twlz0ne Take a look at https://github.com/emacs-lsp/lsp-mode/pull/611 - I believe some of the workarounds discussed in this thread are no longer needed. You may eventually contribute the proper activation command for vue.

2 个赞