silly business

Goodbye lsp-mode

I knew this day would come. I have uninstalled lsp-mode and made the transition to eglot. I've been using lsp-mode since long enough ago that eglot was fairly barebones and it was not obvious which one was the "better" client. Maybe it still isn't obvious.

I tend to prefer a more batteries-included solution; time is short. I picked lsp-mode. But lsp-mode was always kind of janky, to be honest, even if it was very functional. And eglot got upstreamed. It's just an Emacs feature, now. That's not something that happens super often.

The community had spoken. lsp-mode's days were numbered, and now, quite a while actually after the upstreaming of eglot, I have gotten around to removing lsp-mode. eglot was already there, I just needed to start using it.

Taking lsp-mode out of my configuration meant giving up dap-mode too, for some reason that I haven't investigated. They must have been related projects, but I don't use a debugger very often, so it's not something I bothered to look into. It was kind of janky too. Maybe eglot enables something better?

In any case, the overall change was a reduction in complexity and code in my config, and I'm happy about that. And it wasn't too much work.

Some Highlights

eglot requires a lot less configuration than I was expecting because it overloads less of the functionality already present in Emacs. I had read this was the case but I guess I understimated how much of a benefit it is. mea culpa.

After removing all of my lsp-mode-related configuration I only needed to add a couple of things to get functionality the way I like it, with behavior reasonably close to what I am used to from lsp-ui-mode.

Automatic Import Organization and Formatting

For now I only set up Go to start eglot automatically. M-x eglot is not unergonomic, and it keeps surprises down. Go is where I want LSP the most and where I understand best how eglot is going to behave for now:

-  :hook ((go-mode . yas-minor-mode))
+  :hook ((go-mode . yas-minor-mode)
+         (go-mode . eglot-ensure))

I borrowed some code from a GitHub issue comment thread (as you do) to get automatic import organization and formatting on save in Go files – I am spoiled and never think about these things.

   (defun my-eglot-organize-imports () (interactive)
           (eglot-code-actions nil nil "source.organizeImports" t))

   (defun install-my-eglot-organize-imports () 
    (add-hook 'before-save-hook 'my-eglot-organize-imports nil t)
    (add-hook 'before-save-hook 'eglot-format-buffer))

  (add-hook 'go-mode-hook #'install-my-eglot-organize-imports)

Documentation Popups

I was never a huge fan of how eldoc pops up on the bottom of the frame, and it's a big reason why I didn't choose eglot from the beginning. This is a petty personal preference and I am not going to insist that it is a superior preference, however, I want the documentation to pop up at point after a pause. That's what I prefer, so be it.

This code was inspired by (not stolen from) a different GitHub comment which I have unfortunately lost, but good riddance – it was telling me not to use this feature! Hilarious – I have not experienced the alleged performance issues, and in fact, the feature does what I want!

Sometimes it is best to just try things for yourself πŸ€“ You can't believe everything you read on the Internet!

    (use-package eldoc-box)

    ; delay before the pop-up appears
    (setq eldoc-idle-delay 1.5)

    ; load when appropriate
    (add-hook 'eglot-managed-mode-hook #'eldoc-box-hover-at-point-mode t)

The comment (and the docs!) mention the performance impact of eldoc-box-hover-at-point-mode but I haven't noticed it. If I do encounter it, I'll bind it to a key instead of doing the hover.

I like the way elbox-doc looks better than lsp-ui's popups. Woohoo! πŸŽ‰

Keybindings

I'm pretty sure it's a bug in my config (πŸ˜…), so I'm not sure if it's standard or not, but I did have to rebind gd (back?) to evil-goto-definition.

But other than that I haven't found the need to rebind anything so far, which means people who don't already have a configuration with bugs.. might not need any custom keybindings. It seems to integrate well with evil and that sort of thing too, so I think this applies to people with nonstandard setups as well.

Everything I had a custom lsp-mode keybinding set up for, there's a sane default. It might be something a little different than what I had, but something I'm happy enough to learn. For the most part this is because evil-mode already has bindings for certain common actions in code, and eglot is using the key maps that Emacs uses, so evil Just Works with it. The keybindings might be a little different than what I had, but it's likely they will carry over to other Emacs modes and features in the future.

Stuff like gr instead of ,fr to find references, and a greater chance I won't have to change again, and I can maintain less config? That's fine. I'll get used to it.

First Impressions of eglot

After setting up the above features – my must-haves from lsp-mode and lsp-ui ..

.. it's nice. It's real nice. I haven't needed to recreate many of my custom lsp-mode keybindings because the defaults Just Workβ„’.

I should have switched sooner. I just needed to start using it. It was already installed..

#Emacs #Lsp #Eglot