celloworldNavigate back to the homepage

为 emacs lsp python 添加 virtualenv 支持

hidaris
November 4th, 2018 · 1 min read

自从微软的 Language Server Protocol 横空出世后,现代编辑器的使用体验得到了巨大的提升,Emacs 这样的老古董也迎来了第二春。

目前 Emacs 社区实现了两个 lsp client,分别是 lsp-modeeglot,两个客户端的异同比较见 lsp-mode vs eglot,我个人更倾向lsp-mode

在尝试用 lsp 来写 python 的过程中,我发现它不支持 virtualenv,因此在此分享我的解决方案。

我的方法参考了 vscodepycharm,在项目中通过文件的形式记录 virtualenv 的路径,然后加载对应的 virtualenv,再去启动 virtualenv 中的 language server

考虑以上过程,我们需要

  1. 检测项目跟路径来寻找记录文件
  2. 读取文件内容
  3. 根据内容加载 virtualenv

Emacs内置的 project 和社区的 projectile 都可以方便的检测项目的跟路径, 不过 Emacs 内置的文件处理相关的 api 比较粗糙,我采用了 f 这个文件库,另外使用 pyvenv 可以方便的加载 virtualenv

更具体一点

  1. 获取项目跟路径: projectile-project-root
  2. 判断文件是否存在: f-exists?,读取文件: f-read
  3. 加载 virtualenv: pyvenv-workon

最终代码

1(require 'f)
2(require 'subr-x) ;; 字符串处理api
3(require 'projectile nil t)
4
5(use-package pyvenv
6 :ensure t
7 :after python
8 :config
9 ;; 使用conda来管理虚拟环境
10 (setenv "WORKON_HOME" (expand-file-name "~/anaconda3/envs/"))
11 )
12
13(use-package lsp
14 :ensure lsp-mode
15 :after pyvenv
16 :config
17 (add-hook 'python-mode-hook
18 (lambda ()
19 ;; 将项目跟路径与存放virtualenv名称的文件.conda-env拼接成完整的路径
20 (let ((env_file (concat (projectile-project-root) ".conda-env")))
21 ;; 当文件确实存在则读取,否则提示用户
22 (if (f-exists? env_file)
23 (let ((venv_name (f-read env_file 'utf-8)))
24 ;; 去除文件中多余的空格
25 (pyvenv-workon (string-trim venv_name))
26 (lsp))
27 (message "No conda env file found.")))))
28 )

目前,lsp-pythonpython 的支持已经不错了,不过我不是很喜欢 lsp-ui ,并且 pyls 依赖的 jedi 当前版本有无限增加子进程的问题,见 jedi fork大量python进程(update: Fix environment cache regression)。

More articles from hidaris

The Expression Problem Revisited

The Expression Problem is a new name for an old problem. The goal is to define a datatype by cases, where one can add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety (e.g., no casts).

March 13th, 2016 · 1 min read

使用 CDN 优化 Gatsby 站点的访问速度

为博客加上 jsDelivr 全球高速静态资源访问服务

March 14th, 2020 · 1 min read
© 2016–2020 hidaris
Link to $https://twitter.com/zuodadaLink to $https://github.com/hidarisLink to $https://instagram.com/hidaris128