lsp mode awkwardness
cwhatley opened this issue · 7 comments
Do you use lsp-mode in conjunction with poetry.el? I'm using lsp-deferred, but the connection to the language server is still to early to pick up the right env and run pyls from within the venv. I've tried all three tracking strategies.
@cwhatley I've been trying to set up a config like this too. I think I have lsp-python-ms
set up for non-Poetry projects using .dir-locals.el
to manually set the path to the virtual environment's Python binary, but that approach doesn't seem to work for Poetry projects. At the moment I'm trying to add a hook to lsp-python-ms
to check if poetry.el
has found a project root, but I'm running into the same wall as you where the language server connection always starts first before anything else is evaluated.
;; lsp Python
(use-package lsp-python-ms
:after lsp-mode poetry
:ensure t
:init
(setq lsp-python-ms-auto-install-server t)
:config
(put 'lsp-python-ms-python-executable 'safe-local-variable 'stringp)
:hook
(hack-local-variables-hook . (lambda ()
(when ('stringp (poetry-find-project-root))
(poetry-venv-workon)
(print "hello")
)
(when (derived-mode-p 'python-mode)
(require 'lsp-python-ms)
(lsp-deferred))
))
)
@cwhatley I figured it out 🎉 ! Here are the relevant use-package snippets:
;; poetry
(use-package poetry
:ensure t
:hook
;; activate poetry-tracking-mode when python-mode is active
(python-mode . poetry-tracking-mode)
)
;; ....
;; lsp-mode configs
(use-package lsp-mode
:ensure t
:init
(setq lsp-keymap-prefix "C-c l")
:custom
(lsp-auto-guess-root +1)
:config
(lsp-enable-imenu)
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
:hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)
(python-mode . lsp-deferred)
;; if you want which-key integration
(lsp-mode . lsp-enable-which-key-integration)
(lsp-after-open . 'lsp-enable-imenu)
)
:commands (lsp lsp-deferred))
;; lsp Python
(use-package lsp-python-ms
:after poetry
:ensure t
:init
(setq lsp-python-ms-auto-install-server t)
:config
(put 'lsp-python-ms-python-executable 'safe-local-variable 'stringp)
;; attempt to activate Poetry env first
(when (stringp (poetry-find-project-root))
(poetry-venv-workon)
)
:hook
(
(python-mode . (lambda ()
(require 'lsp-python-ms)
(lsp-deferred)
))
;; if .dir-locals exists, read it first, then activate mspyls
(hack-local-variables . (lambda ()
(when (derived-mode-p 'python-mode)
(require 'lsp-python-ms)
(lsp-deferred))
))
)
)
It seems awfully hacky to me, but importantly it works automatically with Poetry projects and projects where I manually define a Python (and mypy) path in a .dir-locals.el
file.
Thanks for the snippet. What's the when...poetry-venv-workon
clause doing in the middle of the lsp-python-ms package statement? That seems to conflict with having poetry tracking mode on.
Sounds like the moral of the story is to not have poetry.el automatically track.
What's the
when...poetry-venv-workon
clause doing in the middle of the lsp-python-ms package statement? That seems to conflict with having poetry tracking mode on.
The poetry.el
init process seems to be too slow, so the connection to the mspyls always happens as soon as the -python-mode-hook
runs. I found that the important part of the init process is the poetry-venv-workon
so mspyls can see the Poetry virtualenv Python binary before it spins up, so I just added that to the package statement.
Sounds like the moral of the story is to not have poetry.el automatically track.
Fully agree – it runs far too slowly and runs the virtualenv activation too late. If it provided a minor mode and a mode-hook, I could use that instead in my package declaration.
I actually use pyls (I should try the MS one, I think) and inspired by your snippet, I tried the following and found this seems to work pretty well so far:
(use-package poetry
:hook
(python-mode . (lambda () (when (poetry-venv-exist-p)
(setq-local lsp-pyls-server-command '("poetry" "run" "pyls"))
(poetry-venv-workon))))
)
Very cool! I only just started using LSP and opted for mspyls since some threads on Reddit suggested it has better performance and is more actively developed.
a better config based on @cwhatley 's
(use-package poetry
:straight t
:config
(poetry-tracking-mode)
)
(use-package python
:mode "python-mode"
:after (poetry)
:hook
(python-mode
. (lambda () (when (poetry-venv-exist-p)
(setq-local lsp-pyls-server-command '("poetry" "run" "pyls"))
)
(lsp-deferred)
)
)
:config
(setq python-indent-guess-indent-offset nil))
(use-package pyvenv
:straight t
:hook (after-init . pyvenv-mode)
)