分享一下我的 LSP 配置文件 (带注释)


#1

Emacs 的 lsp-mode 不太好折腾, 所以分享一下我的个人配置.

LSP (Language Server Protocol) 是微软领导开发的编程语言语法补全和代码分析框架, 好处是全世界黑客都一起开发 LSP 后端, 不论你用的是 Emacs, Vim 还是 Sublime, VSCode, Elicpse, IntelliJ 等编程工具, 都可以享受同等智能的语法补全后端.

Emacs 的 lsp-mode 不太好折腾, 所以分享一下我的个人配置.

```Elisp
;;; Require
(require 'lsp-mode)
(require 'lsp-ruby)
(require 'lsp-python)
(require 'lsp-typescript)
(require 'company-lsp)

;;; Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OS Config ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (featurep 'cocoa)
  ;; Initialize environment from user's shell to make eshell know every PATH by other shell.
  (require 'exec-path-from-shell)
  (exec-path-from-shell-initialize))

;; Enable LSP backend.
(push 'company-lsp company-backends)

;; Configuration to fix LSP errors.
(setq lsp-enable-eldoc nil) ;we will got error "Wrong type argument: sequencep" from `eldoc-message' if `lsp-enable-eldoc' is non-nil
(setq lsp-message-project-root-warning t) ;avoid popup warning buffer if lsp can't found root directory (such as edit simple *.py file)
(setq create-lockfiles nil) ;we will got error "Error from the Language Server: FileNotFoundError" if `create-lockfiles' is non-nil

;; Python support for lsp-mode using pyls.
;; Install: pip install python-language-server
;;
;; When type os. in python file, pyls will crash.
;; So you need clone python-language-server and path https://github.com/palantir/python-language-server/issues/373
;; Then install patched version with command:
;;
;; sudo pip install .
;;
(add-hook 'python-mode-hook #'lsp-python-enable)

;; Ruby support for lsp-mode using the solargraph gem.
;; Install: gem install solargraph
;; NOTE: and you need put below line in your Gemfile, otherwise lsp-ruby will report tcp error.
;;
;; gem "solargraph"
;;
(add-hook 'ruby-mode-hook #'lsp-ruby-enable)

;; Javascript, Typescript and Flow support for lsp-mode
;;
;; Install:
;;
;; npm install -g typescript
;; npm install -g typescript-language-server
;;
;; Fixed error "[tsserver] /bin/sh: /usr/local/Cellar/node/10.5.0_1/bin/npm: No such file or directory" :
;; 
;; sudo ln -s /usr/local/bin/npm /usr/local/Cellar/node/10.5.0_1/bin/npm
;;
(add-hook 'js-mode-hook #'lsp-typescript-enable)
(add-hook 'typescript-mode-hook #'lsp-typescript-enable) ;; for typescript support
(add-hook 'js3-mode-hook #'lsp-typescript-enable) ;; for js3-mode support
(add-hook 'rjsx-mode #'lsp-typescript-enable) ;; for rjsx-mode support

(defun lsp-company-transformer (candidates)
  (let ((completion-ignore-case t))
    (all-completions (company-grab-symbol) candidates)))

(defun lsp-js-hook nil
  (make-local-variable 'company-transformers)
  (push 'lsp-company-transformer company-transformers))

(add-hook 'js-mode-hook 'lsp-js-hook)

#2

我歪个楼 请教两个问题

  1. 请问 typescript 比javascript要好吗? 我觉得应该是要好一些吧!

  2. JavaScript权威指南上有一章是讲鸡肋与精华的,typescript算是鸡肋还是精华呢?

我知道这个没有标准答案,就算一个小插曲吧!


#3

typescript 语法更优雅吧, 其实还是看个人能力, 不在乎剑刃是否锋利.


#4

我觉得TS对C系语言开发者更友好


#5

lsp-mode把eldoc-documentation-function設置成調用textDocument/hoverlsp-ui-doc-mode會把它改成lsp-ui-doc--eldoc,渲染interface Hover中的信息,顯示爲child frame和echo area。

其實LSP還有個textDocument/signatureHelp(我正準備加到ccls),後者對於補全有一點用處,還沒想好UI應該做什麼樣的適配(有的話我的elisp水平也寫不出來,哈哈)

我有空一點也想看看eglot怎麼樣。language server重啓的事看起來大家都有需求,但怎麼一直沒有投入精力好好修好……從eglot可以抄去lsp-mode的。


#6

我这里 c-mode 一起动 eglot 整个编辑器就无响应😅

[jsonrpc] (warning) Sentinel for EGLOT (~/c-mode) still hasn't run,  deleting it!

#7

我这边M-x运行eglot,有时候会不返回,就是没法再运行其他命令,需要C-g结束才行。不知道eglot怎么会设计成这样。

另外,搭配clangd使用(其他没试),对于包含snippet的补全,snippet占位字符显示后,竟然要延迟几百毫秒后,snippet的高亮才显示,实在是让人惊讶。也不是因为加载yasnippet,yasnippet自身运行正常


#8

目前阶段混用 lsp-mode 和 eglot 吧, lsp-mode 的 ruby 支持太差了.


#9

eglot沒有對castwide/solargraph (Ruby language server)的適配。

https://github.com/emacs-lsp/lsp-ruby/blob/master/lsp-ruby.el 沒有多少行。

想知道它的Ruby支持怎麼差……而且你應該很容易就把這個改好的吧。


#10

kill ruby buffer 会导致 LSP 端口被占用后, 无法通讯.

我看到社区已经有补丁了: https://github.com/emacs-lsp/lsp-ruby/pull/1

最近比较懒, 不想研究 lsp


#11

这种补丁应该提给 lsp-mode,从顶层解决问题,让其他语言也受益。

lsp-mode 都搞那么复杂了,竟然这些基本的问题都不解决。

我对 lsp-mode 的另一个不满,是无法在临时 buffer (比如 org-edit)使用。


#12

根據specification,多數client->server requests都會接收這樣的參數描述當前document:

(define-inline lsp--text-document-identifier ()
  "Make TextDocumentIdentifier.

interface TextDocumentIdentifier {
    uri: string;
}"
  (inline-quote (list :uri (lsp--buffer-uri))))

可以研究下怎麼讓temp buffer用上其關聯的buffer的filename

另外小心怎麼讓textDocument/didOpen ``textDocument/didChange`等有意義。


#13

最新版的 lsp-ruby 已经修复了这个问题, 不会因为 kill-buffer 导致端口被占用的问题