Out of the box, Emacs is a very powerful text editor, but it isn’t an IDE. It misses a lot of features like checking your code for build errors, jumping to a symbol’s definition, renaming a symbol across your whole project, etc.
This post shows how I’ve set up Emacs to make it comfortable for me to edit C++ in, but it is not a beginner’s guide to Emacs so I assume that you are already comfortable with the basics. If you are stuck, try the excellent built-in help system or have a look at my cheatsheet.
There are a few ways to add these features, for example the ctags/etags system1 that comes with Emacs, but my favourite solution is using an LSP server like
clangd. It runs outside of Emacs and communicates via HTTP, and can be instructed to inspect a file, or to rename or format something.
Before starting, you will need to have
clangd installed. It is available in Debian Testing and in Debian Backports2 as
clangd-8. In Gentoo Linux it comes as a part of the main
The first thing in my
~/.emacs.d/init.el ensures that
use-package is installed. It is a cool macro that allows you to configure packages in a tidy way, and also tell your package manager to install a package if it is absent.
require 'package) (setq package-user-dir (expand-file-name "elpa" user-emacs-directory) ( package-archives"gnu" . "https://elpa.gnu.org/packages/") '(("melpa" . "https://melpa.org/packages/")) (t) use-package-always-ensure unless (bound-and-true-p package--initialized) ( (package-initialize))unless package-archive-contents ( (package-refresh-contents))unless (package-installed-p 'use-package) ( (package-install 'use-package)) (eval-when-compilerequire 'use-package)) (
CMake Syntax Highlighting
For editing CMake scripts, I will use the
cmake-mode package. It isn’t particularly smart, so I also install the
cmake-font-lock package to make the syntax highlighting type aware.
use-package cmake-mode ("CMakeLists\\.txt\\'" "\\.cmake\\'")) :mode (use-package cmake-font-lock ( :after (cmake-mode) :hook (cmake-mode . cmake-font-lock-activate))
Company is a completion framework for Emacs. It comes with some auto-completion for CMake scripts and for Emacs Lisp, and it can also get completions from our LSP client when installed later.
use-package company ( :hook (prog-mode . company-mode))
prog-mode hook means that company will be loaded in any buffer with a programming language mode (so not for Org or Markdown files). If you only wanted completions for C/C++, you could change this to
Ivy is like Company, but for your minibuffer (e.g. finding files with
C-x f, entering a command with
use-package ivy (0.1 :defer :config (ivy-mode))
Later on the
lsp-ivy command can be installed so that Ivy’s fuzzy finding goodness can be used to search through all of the symbols in your project.
Finally, the LSP client
lsp-mode can be installed and configured.
lsp-ivy is also installed.
use-package lsp-mode ( :hook (c-mode-common . lsp-deferred) :commands (lsp lsp-deferred) :custom1) (lsp-idle-delay (lsp-completion-provider :capf)nil) (lsp-enable-file-watchers "s-l")) (lsp-keymap-prefix use-package lsp-ivy ( :commands lsp-ivy-workspace-symbol)
clangd to work properly, it requires a database of compile commands to be in your project’s root. CMake can be instructed to generate this file (and keep it up to date) if you set the
Here’s how I would configure a project and symlink the compile commands database:
git clone https://git.some-project.org/project.git cd project cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ln -s build/compile_commands.json . make -Cbuild
Note that this option is only implemented by the Makefile and Ninja generators.
After the compile commands database is generated, open one of the source files and press
i to start the
clangd server and set the project root.
Try searching for a symbol with
M-x lsp-ivy-workspace-symbol, renaming a symbol with
s-l r r, formatting the file with
s-l = =, or writing some invalid code and observing the error.
Requests are sent to the LSP server as JSON, and also responses are also received as JSON. Emacs 27 includes a native JSON parser, so you should see a nice performance improvement by switching to Emacs 27.
Additionally, these responses can be very large. If you notice Emacs freezing a lot, try increasing gc-cons-threshold and read-process-output-max. Put these lines near the top of your
init.el, or in
early-init.el if on Emacs 27.
setq gc-cons-threshold (* 512 1024 1024) (* 1 1024 1024)) read-process-output-max (
There are a lot of key bindings to set and remember, so
which-key-mode can show the possible key bindings as you type them.
Install the package and enable it globally:
use-package which-key ( :config (which-key-mode))
Add hook to LSP mode:
use-package lsp-mode ( :hook ((c-mode-common . lsp-deferred) (lsp-mode . lsp-enable-which-key-integration));;; Rest of the configuration...
After installing all of these packages, your modeline might be full of junk. You can install the diminish package to hide some of the modes that aren’t useful to have there.
Firstly install diminish:
:diminish keyword to any modes that you want to hide, e.g. the
use-package which-key call now becomes:
use-package which-key ( :diminish :config (which-key-mode))
Compiling and Running Tests
For now I open an
eshell buffer that I enter commands into like
ctest manually. If you know of any way that I can run my tests from Emacs and get a report, please contact me so that I can add it to this post.