LSP (Language Server Protocol) 是微软领导开发的编程语言语法补全和代码分析框架, 好处是全世界黑客都一起开发 LSP 后端, 不论你用的是 Emacs, Vim 还是 Sublime, VSCode, Elicpse, IntelliJ 等编程工具, 都可以享受同等智能的语法补全后端.
Emacs 的 lsp-mode 是LSP协议在Emacs的客户端实现.
lsp-mode现在能够很好的支持 C++, Python, Ruby, Golang, Haskell, OCamel, Rust, PHP等语言.
当然也包括 JavaScript.
lsp-mode 对 JavaScript 的默认补全主要靠 javascript-typescript-langserver 这个后端来实现.
tide 使用的是 tsserver, 也就是微软给 VSCode 开发的JavaScript智能补全后端, 可以很好的支持 JavaScript 和 TypeScript.
安装方法
1. 安装 tsserver 补全后端
npm install -g typescript
npm install jquery --save
- typescript 这个包会安装 tsserver
- jquery --save 这个包安装以后, tsserver 就不会抱怨找不到 JQuery 的 $ 符号了 ;)
2. 安装 tide
从 https://github.com/ananthakumaran/tide 下载源码后放到 Emacs 的加载目录后, 把下面代码写入 ~/.emacs 中:
(require 'tide)
(dolist (hook (list
'js2-mode-hook
'rjsx-mode-hook
'typescript-mode-hook
))
(add-hook hook (lambda ()
;; 初始化 tide
(tide-setup)
;; 当 tsserver 服务没有启动时自动重新启动
(unless (tide-current-server)
(tide-restart-server))
)))
体验
打开 *.js 文件后, tide 会自动把当前目录识别为 root 目录 (这对于大部分的 WebPack 项目来说已经是足够了的)
其他比较有用的命令:
- tide-jump-to-definition: 跳转到函数或变量定义的地方
- tide-jump-back: 跳转定义以后再跳转回来
- tide-rename-symbol: 语法重命名符号
- tide-rename-file: 重命名JS文件
也可以像这样用 tide-references
命令查找符号所有语法引用的地方.
更多命令请参考 Tide github
lsp-mode 使用 typescript-language-server 后端
前面说的 lsp-mode 默认使用 javascript-typescript-langserver 这个后端, 其实换成 typescript-language-server (tsserver 的封装) 也可以达到 tide 的同样效果, 类似的配置如下:
(require 'lsp-typescript)
;; 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)
备注
请直接使用js-mode, 不要使用 js2-mode 或者基于 js2-mode 的插件(比如 rjsx-mode), js2-mode 会导致编辑 JS 文件时非常非常卡顿.