Emacs: Sane lsp-mode snippets with clangd
If you use clangd
as your language server for Emacs’ lsp-mode
, you
may have a setup similar to the following:
(use-package lsp-mode
:after
yasnippet
:init
(setq lsp-keymap-prefix "C-c l"
lsp-enable-indentation nil
lsp-enable-on-type-formatting nil)
:hook
(prog-mode . lsp-deferred) ;; defer until a source code buffer is open
(lsp-mode . lsp-enable-which-key-integration)
:commands
(lsp lsp-deferred)
:config
(define-key lsp-mode-map (kbd "C-c l") lsp-command-map)
:custom
(lsp-clangd-binary-path "/usr/bin/clangd")
(lsp-headerline-breadcrumb-enable t)
(lsp-modeline-code-actions-enable t)
(lsp-enable-suggest-server-download nil)
(lsp-warn-no-matched-clients nil)
(lsp-idle-delay 0.1)
(gc-cons-threshold (* 100 1024 1024))
(read-process-output-max (* 1024 1024))
(lsp-clients-clangd-args
'("-j=4"
"--header-insertion=never"
"--all-scopes-completion"
"--background-index"
"--clang-tidy"
"--compile-commands-dir=build"
"--cross-file-rename"
"--suggest-missing-includes")))
This works pretty nicely, especially if you use meson
as your build
system and define your build directory as “build” (which is where your
compile_commands.json
will end up).
However, I noticed that the default “snippets” recommended by clangd
in the company popup menu were horribly formatted, requiring me to
mess with the formatting and wasting time after insertion. It took me
a while to find the root cause, but I ultimately found a solution that
works much better for me, providing sane snippets for common blocks of
code such as if
and switch
.
By
default,
lsp-mode
uses company-capf
as the completion provider (the source
of the recommended items in the popup menu). This is great, but
doesn’t allow us to use nice snippets available in the
yasnippet-snippets
package. It would be better if we could combine
multiple company backends, making using of company-yasnippet
as
well.
Luckily this is pretty straightforward. First we need to disable the
lsp-mode
configurations for company
by including the following
line in the use-package
configuration:
(setq lsp-completion-provider :none)
This will allow us to override the completion provider with multiple
company
backends. We also want to disable the terrible clangd
snippets from showing up in our company-capf
recommendations by
including the following line in our lsp-mode
use-package
configuration:
(setq lsp-enable-snippet nil)
Our final use-package
:init
block for lsp-mode
looks like this:
...
:init
(setq lsp-keymap-prefix "C-c l"
lsp-enable-indentation nil
lsp-enable-on-type-formatting nil
lsp-completion-provider :none
lsp-enable-snippet nil)
...
Now all that’s left is to configure our company
backends. We can do
that easily by adding the following line to our company
use-package
configuration:
...
:init
(setq company-backends '((company-capf company-yasnippet)))
...
Of course, you may want to set different backends depending on the type of major-mode you’re in, but I’ll leave that up to you to figure out. :)
Hopefully this helps you get useful snippets while using lsp-mode
with clangd
. Enjoy!
Get in touch with me at dev@mailcd.com!