Johan Bolmsjö's GNU Emacs Configuration
Installation instruction:
git clone github.com/johan-bolmsjo/emacs.d ~/.emacs.d
Table of Contents
1. The Init File
Requires GNU Emacs version 28.1 or greater.
The main init file is init.el
.
This file loads packages that require external programs to function properly.
See chapter 3 for how to install required programs for specific packages.
1.1. Overview
Overview of enabled packages.
1.1.1. Package Management
Emacs packages are installed using the straight package manager. The advantage with this package manager is that it keeps the complete upstream Git repositories available together with lock files to pin down exact versions. This means that the Emacs configuration is reproducible. It's also possible to easily change package versions to resolve incompatibilities when the configuration is copied between hosts with different Emacs versions.
The version lock file ~/.emacs.d/straight/versions/default.el
is versioned by this Git repository.
The actual upstream package source code is not managed by this Git repository.
They are downloaded by Emacs when started.
For local backup purposes it's possible to just archive the whole ~/.emacs.d
directory.
It's transferable between machines.
1.1.2. Documentation Modes
1.1.4. Programming Languages Modes
1.1.5. Miscellaneous Support Functions
- Improved minibuffer completions through Vertico, Marginalia and Orderless.
- Collection of minibuffer utilities provided by Consult.
- Context aware minibuffer actions through Embark.
- Code completion through Corfu and Orderless.
- Templated auto complete assisted snippets through Yasnippet.
- Project like IDE support using Treemacs, project.el and Eglot.
- Compiler diagnostics through Flycheck or Flymake.
- Git interface through Magit.
- GDB support through GUD.
- Extraneous whitespace indications.
1.2. Keybindings
Keybindings that are specific to this configuration file.
1.2.1. User Keybindings
See https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Binding-Conventions.html for user keybinding conventions. Also http://xahlee.info/emacs/emacs/keyboard_shortcuts.html for practical overrides.
C-c a
align-current
C-c c
compile
C-c g
find-grep
C-c i
ispell-region
C-c o
ff-find-other-file
(in c-mode-common)C-c s
sort-lines
C-c t
- toggle treemacs pane
Incremental Search
C-c k
- Set mark at start of current match and exit isearch (user function).
Navigation
Even though these functions are called error
, they work in many contexts. E.g. moving through compilation errors, grep results, xref references.
F9
next-error
F10
prev-error
(overrides global menu popup)
Window Management
Commands useful to prevent Emacs from splitting frames and replacing buffers in windows when doing certain tasks.
C-c F
- Lock current frame for automatic splitting.
C-c f
- Unlock current frame for automatic splitting.
C-c W
- Lock current window to its current buffer.
C-c w
- Unlock current window from its current buffer.
See https://smythp.com/emacs_buffers/ for an explanation of the frames, windows and buffers terminology.
Denote
C-c n
- Command prefix
The main note taking command is C-c n n
.
Other keybindings are listed when entering the command prefix.
Discover all commands by entering M-x denote
Org Mode
C-c p
org-agenda
(planning)C-c L
org-store-link
(works in other modes to store links)
Eglot Mode
Note that eglot relies on the keybindings of other packages for most functions. E.g. xref for navigation and eldoc for documentation.
C-c e a
eglot-code-actions
C-c e f
eglot-format
(ask server to format buffer or the active region)C-c e r
eglot-rename
(rename symbol at point)C-c e i
eglot-find-implementation
C-c e t
eglot-find-typeDefinition
Flymake Mode
Aligned with flycheck counterparts.
C-c ! l
flymake-show-buffer-diagnostics
C-c ! n
flymake-goto-next-error
C-c ! p
flymake-goto-prev-error
Embark
Embark executes context aware actions. For example opening the URL that the cursor is placed on in a buffer. It extends some of the consult commands by making it possible to export the current selection to regular buffers for easier manipulation.
C-.
- Execute action
C-;
- "Do what I mean"
C-h B
embark-bindings
; alternative for `describe-bindings'
Note that C-.
may be hijacked as a system shortcut to insert a Unicode code point or Emoji.
Disable it in ibus-settings
on Linux systems.
GDB (debugger)
F5
- Continue program being debugged.
F6
- Step till next source line, do not enter subroutine (next).
F7
- Step till next source line, enter subroutine (step).
F8
- Execute until current stack frame returns.
S-F8
- Stop debugging
1.2.2. Overridden Keybindings
Modifies standard Emacs behavior or use non-user prefix.
F10
prev-error
(overrides global menu popup)M-n
scroll-up-command
M-p
scroll-down-command
M-f
forward-symbol
(replaces forward-word)M-b
my/backward-symbol
(replaces backward-word)M-C-f
forward-paragraph
(replaces forward-sexp)M-C-b
backward-paragraph
(replaces backward-sexp)C-x k
my/fast-kill-buffer
(replaces kill-buffer)
1.3. User Facing Functions
Convenience functions defined by the configuration.
reload-file
- Calls
revert-buffer
without asking for confirmation
1.4. Configuration Adaptations
Configuration adaptations that may be desired when applying this Emacs configuration in a new environment.
1.4.1. Terminal Emulator
The solarized theme that is used by this Emacs configuration only works properly in graphical mode and terminals that support true color.
The website https://github.com/termstandard/colors describes how to configure terminals and associated tools to support true color.
In essence, the environment variable COLORTERM
must be set to truecolor
.
COLORTERM
is distinct from the usual TERM
environment variable that communicate terminal capabilities.
Obviously the underlying terminal must also support the true color escape codes.
My ~/.bashrc
contains the following lines to set it for the suckless terminal:
# Set the COLORTERM variable to "truecolor" if the terminal supports it. # The suckless terminal (st) definitely does. # The tmux-256color can be any underlying type so is technically incorrect; # it solves the issue of SSH to remote system from within a Tmux session. if [ "$TERM" = st-256color ] || [ "$TERM" = tmux-256color ]; then export COLORTERM=truecolor fi
1.4.2. Shell Environment optional
You may want to source ~/.emacs.d/etc/bashrc
from your ~/.bashrc
file.
Read the small script to find its purpose.
if [ -f ~/.emacs.d/etc/bashrc ]; then . ~/.emacs.d/etc/bashrc fi
You may also want to source ~/.emacs.d/etc/profile
from your ~/.profile
or ~/.bash_profile
to add ~/.emacs.d/bin
to the program search path.
if [ -f ~/.emacs.d/etc/profile ]; then . ~/.emacs.d/etc/profile fi
1.4.3. Fonts optional
A personal choice, my current favorite monospaced fonts can be found in the ~/.emacs.d/fonts/gofont
directory.
Installation (Linux):
mkdir -p ~/.fonts cp ~/.emacs.d/fonts/gofont/*.ttf ~/.fonts
Update ~/.emacs.d/fonts.el
with your preferred fonts and default size.
1.4.4. Indexed Grep
I've opted to replace the grep-find
command with a wrapper script that invokes a grep program based on an index.
This speeds up grep operations in large code bases massively but it may not be to your liking.
Just delete the entire section "Indexed grep search tool" from ~/.emacs.d/init.el
to restore the original behavior.
See section 3.1 for details.
1.4.5. Custom Variables
Variables that may need customization (such as file paths) are stored in ~/.emacs.d/custom.el
.
2. Quick Guides
Scattered quick guides for my own memory. It could do with more information for Emacs neophytes.
2.1. Navigation
Xref is used by many Emacs modes for navigation, including Eglot for navigating source code.
M-,
- Go back
M-.
- Find thing
M-?
- Find references
Jump to a specific line.
M-g g
- goto-line
2.2. Incremental Search
Don't forget about the occur mode when doing incremental search. It's very useful to get a navigable outline of all current matches.
All keybindings can be listed by invoking C-h b
when in search mode.
Starting search:
C-s
- Search forward for a literal string
C-r
- Search backward for a literal string
C-M-s
- Search forward for a regexp
C-M-r
- Search backward for a regexp
M-s _
- Search forward for a symbol
M-s .
- Search forward for the symbol at point
During search:
C-s
- Move to next match (
C-s C-s
to resume search) C-r
- Move to previous match (
C-r C-r
to resume search) C-g
- Abort search
M-c
- Toggle case sensitive search
M-e
- Edit search term
M-s o
- Outline of current matches (occur)
M-s SPC
- Toggle lax whitespace
RET
- Terminate search, leaving cursor at the current match
2.3. Completion in Buffers
Completion is provided by Corfu together with Orderless.
Completion is triggered by C-M-i
which is bound to complete-symbol
.
The TAB key is also configured to either indent (if it can), else complete.
This does not work in the C/C++ mode.
The completion mechanism provided by orderless is a bit different and can take some time to get used to.
Multiple patterns (space separated words) can be entered.
Completions candidates that match all patterns regardless of order are kept.
Patterns can be regexps as well as regular words, e.g. ^desc
match candidates starting with desc
.
The built-in dabbrev mode can also be useful.
M-/
- dabbrev-expand
C-M-/
- dabbrev-completion
2.4. Minibuffer Completion
Vertico together with Marginalia and Orderless is used to enhance minibuffer completions.
For example selecting buffers, files or the function to invoke via M-x
.
TAB
- Navigate to selected candidate
RET
- Accept selected candidate
M-RET
- Submit exactly what is typed (ignore candidate completion)
C-g
- Abort (as always)
Searching for previous selections is done using C-s
and C-r
.
Navigation is performed using the usual keybindings.
2.5. Magit
Magit is a complete text-based user interface to Git.
The magit status command is bound to C-x g
.
2.6. Denote
The YouTube presentation https://www.youtube.com/watch?v=mLzFJcLpDFI by the package author gives a good overview of the note taking workflow. I recommend studying the manual for further details.
2.7. Org Mode
Org mode is a documentation and planning major mode. Some HOWTO notes are kept in docs/howto-org-mode.html.
The org-tempo
package is enabled which provides some template instantiation shortcuts.
Invoke M-x describe-variable
and enter org-tempo-tags
to see all shortcuts.
Useful shortcuts include <s
TAB for source blocks and <q
TAB for quote blocks.
2.8. Text Templates
Text template support is provided by the yasnippet package. Sippets are kept under
~/.emacs.d/<MODE>/<FILE>
and they are are expanded by typing their name and pressing
TAB.
2.9. Diagnostics
Diagnostics such as compiler errors are provied by either the flycheck or flymake package.
2.10. Language Server Protocol Support
Eglot works in concert with project.el to identify projects. Only version controlled directories can become projects. Eglot can only analyze files that belongs to a project.
Invoke M-x p p
to add a project, select the … (choose a dir) option.
Tracked projects are stored in ~/.emacs.d/projects
.
Eglot must be started manually from an opened file that belongs to a project.
This is done by invoking M-x eglot
.
Eglot may ask for the language server to use if it can't find one or there are multiple choices.
After having done this once, eglot does not prompt for other files in the same project.
Eglot is well integrated with core Emacs packages.
Apart from the mentioned xref it use the eldoc package to display documentation and type information.
Invoke C-h .
to show documentation at point.
2.11. Keyboard Macros
Keyboard macros are incredibly useful to apply repetitive changes in close proximity.
Press F3
to start recording key presses.
Press F4
to end the recording and bind it to the same key.
2.12. Debugging Using GDB
Activate by M-x gdb
followed by M-x gdb-many-windows
.
The toolbar contain debugger navigation icons so you may want to enable it using M-x tool-bar-mode
.
Keybindings are listed in section GDB (debugger).
3. Setup of External Tools
Unfortunately the Emacs init file is not self contained. External tools are required to support many packages.
3.1. Indexed Grep
The tool codesearch provides fast, indexed regexp search over large file trees.
Install the following commands (requires Go toolchain).
go install github.com/johan-bolmsjo/codesearch/cmd/{cindex,csearch}@latest
Note that the only integration is that the grep-find
command has been changed to invoke ~/.emacs.d/bin/csearch-color
instead.
The convenience scripts in ~/.emacs.d/bin/
has the following purpose:
cindex-append
- Scan directories for source files to add to code index.
cindex-reset
- Clear code index.
csearch-color
- Colorize grep matches for Emacs.
3.2. Shell Script Mode
Install the shellcheck linter to get good advice on shell script constructs.
Ubuntu/Debian specific instruction:
apt install shellcheck
3.3. PlantUML Documentation
3.4. Go Programming Language Mode
Install the Go programming language toolchain as instructed on https://go.dev/dl/
Install required tools:
go install golang.org/x/tools/gopls@latest go install golang.org/x/tools/cmd/goimports@latest go install golang.org/x/tools/cmd/gorename@latest go install github.com/rogpeppe/godef@latest
3.5. OCaml Programming Language Mode
Install the OCaml language toolchain from https://ocaml.org/releases/
Install required tools:
opam update opam switch create 4.13.1 opam install dune utop ocaml-lsp-server merlin tuareg ocp-indent odig
The OCaml setup is a bit special in that the Emacs packages are installed by the steps above. Not by the Emacs package manager.
3.6. Python Programming Language Mode
3.6.1. Python Virtual Environments
Pyenv is used to compartmentalize python installations and make it possible to switch between them for different projects.
Install pyenv from https://github.com/pyenv/pyenv:
Clone the pyenv repo:
git clone https://github.com/pyenv/pyenv.git ~/.pyenv cd ~/.pyenv && src/configure && make -C src
Put the following in ~/.bashrc
:
export PYENV_ROOT="$HOME/.pyenv" if [ -d "$PYENV_ROOT" ]; then command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" fi
Apply the changes in the current shell (or login again):
exec "$SHELL"
Install Python build dependencies (Ubuntu specific, refer to https://github.com/pyenv/pyenv/wiki#suggested-build-environment for other OSes):
sudo apt-get update sudo apt-get install make build-essential libssl-dev zlib1g-dev libbz2-dev \ libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils \ tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
Install a Python version using pyenv:
pyenv install 3.10.7
Switching between Python versions:
pyenv shell VERSION
- Select just for current shell session.
pyenv local VERSION
- Automatically select whenever you are in the current directory (or its subdirectories).
pyenv global VERSION
- Select globally for your user account.
3.6.2. Language Server
Install the language server:
pip install 'python-language-server[all]' scrapy
3.7. Zig Programming Language Mode
- Install the language toolchain from https://ziglang.org/download/
- Install the language server from https://github.com/zigtools/zls/
4. Compiling GNU Emacs
Compiling GNU Emacs from source is quite easy. Many packages see heavy development and may require a recent version.
4.1. Emacs 28.2
Install dependencies (Ubuntu 22.04 specific):
sudo apt install \ libcairo2-dev \ libgccjit-11-dev \ libgif-dev \ libgnutls28-dev \ libharfbuzz-dev \ libjansson-dev \ libjpeg-dev \ libncurses-dev \ libtiff-dev \ libxaw7-dev \ libxml2-dev \ libxpm-dev
Download, configure, build and install GNU Emacs on Linux:
wget https://ftp.acc.umu.se/mirror/gnu.org/gnu/emacs/emacs-28.2.tar.xz tar xf emacs-28.2.tar.xz cd emacs-28.2 ./configure \ --with-native-compilation \ --with-mailutils \ --with-x-toolkit=lucid \ --prefix=$HOME/.local make -j16 make install
Make sure that Cairo is used for the GUI in the configure stage or some library dependency is missing.
4.2. Emacs 29.1
Install dependencies (Ubuntu 22.04 specific):
sudo apt install \ libcairo2-dev \ libgccjit-11-dev \ libgif-dev \ libgnutls28-dev \ libharfbuzz-dev \ libjansson-dev \ libjpeg-dev \ libncurses-dev \ librsvg2-dev \ libsqlite3-dev \ libtiff-dev \ libtree-sitter-dev \ libxaw7-dev \ libxml2-dev \ libxpm-dev
Download, configure, build and install GNU Emacs on Linux:
wget https://ftp.acc.umu.se/mirror/gnu.org/gnu/emacs/emacs-29.1.tar.xz tar xf emacs-29.1.tar.xz cd emacs-29.1 ./configure \ --with-native-compilation \ --with-mailutils \ --with-x-toolkit=lucid \ --with-tree-sitter \ --prefix=$HOME/.local make -j16 make install
Make sure that Cairo is used for the GUI in the configure stage or some library dependency is missing.
Install tree-sitter language grammar files using M-x treesit-install-language-grammar
;
example language names: python, c, cpp.
See https://www.masteringemacs.org/article/how-to-get-started-tree-sitter for an introduction to Emacs tree-sitter support and how to use it.
For now, none of the tree-sitter major modes are enabled by default.