Introduction
I normally do most of my development in full-featured IDEs such as CLion or RubyMine, but occasionally they’re overkill for the development platform.
So I’ve put together this short guide on setting up emacs to work with clangd, so that it can be used as a language server to help with C++ code development, and also solargraph for Ruby development, both via the magic of LSP. This is a much lighter weight way of working.
Alternatives include CEDET or Spacemacs, but they bundle a crazy amount of stuff and it’s hard to keep track of which plugins are fighting which other plugins. Even Doom Emacs is a bit much sometimes. The approach used here is just basic emacs plus the minimum needed for clangd to help us. The combination to be used is:
One obstacle is that the default package repository ‘elpa’ is not as full or as current as ‘melpa’, so we first need to set that up so that things will work as needed.
Keep in mind that this is intended as a minimal/lightweight system that works for both C++ and Ruby. There’s a huge amount of stuff that could be added but is out of scope of this guide.
Prerequisites
Some items are taken from the distro repository as-is, others we install from source.
For Debian-based distributions, install things from repository:
sudo apt install clang clang-tools clangd cmake
On macOS I’m using HomeBrew, using the cask version of emacs.
Process
Start with a clean slate:
cd && rm -rf .emacs.d
Start emacs and then exit to allow it to create .emacs.d/
Start emacs again, and then edit ~/.emacs
to add this initial content:
(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize)
Restart emacs and then do M-x package-refresh-contents
, and then install eglot:
M-x package-install RET eglot RET
Restart emacs (just in case). Install company:
M-x package-install RET company RET
Edit ~/.emacs
to make things work automatically, adding the following content:
(require 'eglot) (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd")) (add-hook 'c-mode-hook 'eglot-ensure) (add-hook 'c++-mode-hook 'eglot-ensure) (add-hook 'after-init-hook 'global-company-mode)
Restart emacs. Now, edit a C++ source file which needs to be described by a compile_commands.json
which needs be in the source directory or a parent of it
Hopefully now all is good. If you “mouse over” an identifier, emacs will highlight all uses and also show some context.
extra: clang-format
Assuming you have a .clang-format
file or symlink in your home directory, and that clang-format
has been installed.
Install the clang-format emacs package:
M-x package-install RET clang-format RET
Add this to ~/.emacs
:
(require 'clang-format) (global-set-key (kbd "C-c i") 'clang-format-region) (global-set-key (kbd "C-c u") 'clang-format-buffer) (setq clang-format-style "file")
This allows you to press ^Cu to reformat the current buffer. TODO: Make this also happen on file save.
extra: modern C++ font
This package improves syntax highlighting of C++20 code.
Install the modern-cpp-font-lock
emacs package:
M-x package-install RET modern-cpp-font-lock RET
Add this to ~/.emacs
:
(require 'modern-cpp-font-lock) (modern-c++-font-lock-global-mode t)
Ruby
This uses solargraph as a language server which integrates easily with eglot which we’ve already configured. Install solargraph (which takes a bit of time):
gem install solargraph solargraph download-core
Then you need to manually start solargraph, e.g.:
solargraph socket
Then use emacs to open Ruby source code. You’ll first need to tell eglot to connect to solargraph like this:
M-x eglot RET
TODO: Automate things so that solargraph gets started as needed, and then eglot connects to it as needed.
Updating packages
You should occasionally perform an update of the emacs packages:
M-x list-packages (wait a bit) Press U and then x
Further info
These shortcuts are useful:
M-. will jump to definition M-? will show references
Useful references: