Emacs as a minimal C++ IDE

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:

  • eglot (an emacs LSP client)
  • company (text completion framework)

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: