Posts tagged "lsp-mode":
Trying eglot, again
I've been using lsp-mode since I switched to Emacs several years ago. When eglot
made into Emacs core I used it very briefly but quickly switched back. Mainly I
found eglot a bit too bare-bones; I liked some of the bells and whistles of
lsp-ui. Fast-forward a few years and I've grown a bit tired of those bells and
whistles. Specifically that it's difficult to make lsp-ui-sideline and
lsp-ui-doc work well together. lsp-ui-sidedline is shown on the right side,
which is good, but combining it with lsp-ui-doc leads to situations where the
popup covers the sideline. What I've done so far is centre the line to bring the
sideline text out. I was playing a little bit with making the setting of
lsp-ui-doc-position change depending on the location of the current position.
It didn't work that well though so I decided to try to find a simpler setup.
Instead of simplifying the setup of lsp-config I thought I'd give eglot
another shot.
Basic setup
I removed the statements pulling in lsp-mode, lsp-ui, and all
language-specific packages like lsp-haskell. Then I added this to configure
eglot
(use-package eglot
:ensure nil
:custom
(eglot-autoshutdown t)
(eglot-confirm-server-edits '((eglot-rename . nil)
(t . diff))))
The rest was mainly just switching lsp-mode functions for eglot functions.
| lsp-mode function | eglot function |
|---|---|
lsp-deferred |
eglot-ensure |
lsp-describe-thing-at-point |
eldoc |
lsp-execute-code-action |
eglot-code-actions |
lsp-find-type-definition |
eglot-find-typeDefinition |
lsp-format-buffer |
eglot-format-buffer |
lsp-format-region |
eglot-format |
lsp-organize-imports |
eglot-code-action-organize-imports |
lsp-rename |
eglot-rename |
lsp-workspace-restart |
eglot-reconnect |
lsp-workspace-shutdown |
eglot-shutdown |
I haven't verified that the list is fully correct yet, but it looks good so far.
The one thing I might miss is lenses, and using lsp-avy-lens. However,
everything that I use lenses for can be done using actions, and to be honest I
don't think I'll miss the huge lens texts from missing type annotations in
Haskell.
Configuration
One good thing about lsp-mode's use of language-specific packages is that
configuration of the various servers is performed through functions. This makes
it easy to discover what options are available, though it also means not all
options may be available. In eglot configuration is less organised, I have to
know about the options for each language server and put the options into
eglot-workspace-configuration myself. It's not always easy to track down what
options are available, and I've found no easy way to verify the settings. For
instance, with lsp-mode I configures HLS like this
(lsp-haskell-formatting-provider "fourmolu")
(lsp-haskell-plugin-stan-global-on nil)
which translates to this for eglot
(setq-default eglot-workspace-configuration
(plist-put eglot-workspace-configuration
:haskell
'(:formattingProvider "fourmolu"
:plugin (:stan (:global-on :json-false)))))
and I can verify that this configuration has taken effect because I know enough about the Haskell tools.
I do some development in Python and I used to configure pylsp like this
(lsp-pylsp-plugins-mypy-enabled t)
(lsp-pylsp-plugins-ruff-enabled t)
which I think translates to this for eglot
(setq-default eglot-workspace-configuration
(plist-put eglot-workspace-configuration
:pylsp
'(:plugins (:ruff (:enabled t)
:mypy (:enabled t)))))
but I don't know any convenient way of verifying these settings. I'm simply not
familiar enough with the Python tools. I can check the value of
eglot-workspace-configuration by inspecting it or calling
eglot-show-workspace-configuration but is there really no way of asking the
language server for its active configuration?
Closing remark
The last time I gave up on eglot very quickly, probably too quickly to be
honest. I made these changes to my configuration over the weekend, so the real
test of eglot starts when I'm back in the office. I have a feeling I'll stick
to it longer this time.