A smarter emacs
I’ve been running Emacs for like 25 years. But I’ve never really configured it with anything fancy.
Sure, I’ve set some shortcut keys, and enabled global-font-lock-mode
and set indent size, but that’s almost it.
Ok, so I also once made an ASCII 3D demo of a spinning cube in Emacs-lisp, but that wasn’t really about Emacs.
All my coding is done in tmux&Emacs. One project gets exactly one tmux
session. Window 0 is emacs. Window 1 is make && ./a.out
(sometimes
split panes to tail logs or run both server and client), and to run
git
commands. The remaining windows are used for various things like
reading manpages etc….
I have that same workflow whether I’m editing a blog post or doing kernel programming.
This way I can work at my desk with large and plentiful screens, and then move to my laptop and everything continues working exactly the same.
tmux I’ve customized, but not done as much with Emacs.
So, step one to get my coding environment to be less 1995, and more 2020: make my editor understand my code, and show me stuff about it.
I’m learning as I’m going, and writing what I’m learning. As always if you see something wrong then please leave a comment.
Code annotations and other semantic understanding
The way to do this is to make your editor talk the Language Server
Protocol (LSP) with something that understands the language. For C++
that’s clangd
.
apt install clangd lsp-mode
Then we need to make this LSP thingy understand how to compile the
code. That’s a bit tricky since there may be system-local defines and
stuff. You may have had to provide flags to ./configure
to make it
build, for example, and without it the code will not make sense to the
checker.
This build information needs to end up in a file called
compile_commands.json
The way I found to do this is using scan-build
.
pip install scan-build
cat >> Makefile.am
lsp:
~/.local/bin/intercept-build make
^D
./bootstrap.sh && ./configure && make clean && make lsp
Now we just need to activate LSP mode in Emacs. That’s done by (lsp
t)
. But better yet, let’s trigger it when loading C++ code.
Let’s add this to ~/.emacs.d/init.el
:
(add-hook 'c++-mode-hook 'development-mode)
(defun development-mode ()
"Start dev stuff"
(interactive)
(lsp t)
(setq show-trailing-whitespace t)
(setq indent-tabs-mode nil))
Ok, that looks WHAT THE FUCK?!
Ok, after some searching let’s add this to ~/.emacs.d/init.el
too:
(custom-set-faces
'(lsp-face-highlight-read ((t (:background "gray"))))
'(lsp-face-highlight-textual ((t (:background "gray"))))
'(lsp-face-highlight-write ((t (:background "SteelBlue1"))))
'(lsp-ui-doc-background ((t (:background "black")))))
Ok, that’s better. And we get nice context aware tab completion. Ok, now I feel like I’ve joined the 21st century.
Auto-format code on save
clang again comes to the rescue. Specifically clang-format
.
apt install clang-format
And more for ~/.emacs.d/init.el
:
(defun clang-format-save-hook-for-this-buffer ()
"Create a buffer local save hook."
(add-hook 'before-save-hook
(lambda ()
(progn
(when (locate-dominating-file "." ".clang-format")
(clang-format-buffer))
;; Continue to save.
nil))
nil
;; Buffer local hook.
t)
)
(add-hook 'c++-mode-hook (lambda () (clang-format-save-hook-for-this-buffer)))
From Stackoverflow.
You’ll need a .clang-format
file in your project directory. I took
the one from GNU
Radio. It’s
not exactly perfect for my tastes, but it’s very close. In any case as
long as it’s not awful it doesn’t matter.
This “let’s stop with the style wars” that Go started I think is great. Here at least within a project it’s great to not even get to decide what the brace style is, but even making it impossible to do it wrong. It’s less thinking, less tweaking. Just focus on the code.
Summary
There, now I’ve advanced the state of my programming environment by about 20 years. If you were already doing this in 1995, then good for you.