Emacs

Organisation:Copyright (C) 2025-2025 Olivier Boudeville
Contact:about (dash) howtos (at) esperide (dot) com
Creation date:Sunday, March 16, 2025
Lastly updated:Sunday, May 18, 2025

Overview

Emacs is a family of free software text editors that are characterised by their extensibility and their ability to be customised at will.

Installation

Quite surprisingly, Emacs still changes a lot (notably in terms of function names), and (Elisp) scripts that work for an Emacs version may not work for the next one. So at least controlling one's version may be of use; run for that emacs --version. We consider using here Emacs 30.1 or more recent.

Of course the best option to install Emacs is to use a (OS-level) package manager, for example: apt-get install emacs - if the supported version is not too ancient.

Otherwise, to perform a manual installation of Emacs on one's user account, it must be first downloaded; one may thus fetch for example emacs-30.1.tar.xz.

Prerequisites may be needed; running - unfortunately as root - apt-get build-dep emacs or alike may be of use, or at least having packages like libgtk-3-dev and librust-tree-sitter-dev installed.

Then:

$ mkdir -p ~/Software/Emacs && cd ~/Software/Emacs
$ EMACS_VERSION=30.1
$ mv ~/Downloads/emacs-${EMACS_VERSION}.tar.xz .
$ tar xvJf emacs-${EMACS_VERSION}.tar.xz
$ cd emacs-${EMACS_VERSION}
# If not having these dependencies:
$ ./configure --with-xpm=ifavailable --with-gif=ifavailable \
--with-tiff=ifavailable --with-gnutls=ifavailable --prefix=${HOME}/Software/Emacs/emacs-${EMACS_VERSION}-install
$ make install
$ cd .. && ln -s emacs-${EMACS_VERSION}-install emacs-current-install

Then one's shell environment shall be updated once for all with:

$ export PATH="${HOME}/Software/Emacs/emacs-current-install/bin:${PATH}"

Configuration

General Configuration

Our base Emacs configuration, init-myriad-base.el, is designed to be minimal enough not to depend on any third-party element (so it is not relying on a package manager).

It may be used as:

  • a simple configuration of its own, for example on servers (hence just on the console, with no GUI), typically once copied or symlinked as ~/.emacs.d/init.el
  • a fallback configuration, useful when a reliable, unaffected editor is needed to debug one's Emacs configuration (see Relying a safe, minimal, fallback Emacs for that) - a base configuration expanded (i.e. included) by more involved / specialised configurations, akin to our main, most complete Emacs configuration for daily usage, init-myriad-fully-integrated

Fonts

  • to display information about the current font: M-x describe-font RET (see also describe-char - when the point is on an actual character)
  • to set the:
    • font used by the current frame: use for example (set-frame-font "JetBrainsMonoNerdFont 10") or (set-frame-font "Iosevka Fixed")
    • default font: use for example (set-default-font "DejaVu Sans Mono 14")

See also:

Topic-specific Configurations

In addition to these previous base or complete configurations, we defined modular, specialised configuration files for a few topics.

First, the standalone ones, i.e. the specialisations that do not depend on any specific (third-party) package (but still depend on our base Emacs configuration, init-myriad-base.el), are:

Now the configurations involving extra, specific packages are discussed.

Regarding Package Management Itself

We rely on init-myriad-package-management.el in order to setup a proper management of Emacs packages. It is a prerequisite of all next configurations below, and is currently based on elpaca.

Regarding Erlang

We propose init-myriad-erlang-advanced.el, to provide additional tooling on top of the prior init-myriad-erlang-base.

It requires erlang_ls, which can be typically obtained thanks to:

$ mkdir -p ~/Software
$ cd ~/Software
$ git clone https://github.com/erlang-ls/
$ cd erlang_ls && make && mkdir bin && cd bin
$ ln -s ../_build/default/bin/erlang_ls
# Then add ${HOME}/Software/erlang_ls/bin to your PATH.

erlang_ls shall be regularly updated (e.g. with: cd ${HOME}/Software/erlang_ls && git pull && make all).

Its per-user configuration can be defined in ~/.config/erlang_ls. We prefer that it is a symbolic link to our own version thereof.

One may refer to ~/Software/erlang_ls/misc/dotemacs for a configuration example.

Wrapping-up Configurations

Finally, an optional local (host-specific) configuration file (to define relevant initial window sizes for that host, any specific proxy, etc.) will be loaded iff found available as ~/.emacs.d/init-myriad-local.el; see this init-myriad-local.el as an example thereof.

All the configuration files that have been listed above are included by the aforementioned init-myriad-fully-integrated.el one.

For the sake of testing, an instance of Emacs relying on a given configuration file (typically init.el) can be best run with: emacs --init-directory=$SOME_DIR, where SOME_DIR contains this configuration file (possibly as a symbolic link); see also Relying a safe, minimal, fallback Emacs to edit concurrently that configuration file in progress.

Hints

Emacs Parlance

With Emacs:

  • a frame is actually a regular GUI window
  • a window is a subdivision of a frame (hence to be understood as a window pane)
  • a buffer is the content shown in a window
  • (the) point is the (current) cursor position
  • the mark is the beginning of the current selection (typically set by C-SPC at the current point)
  • ELPA stands for Emacs Lisp Package Archive (see more package-related explanations):
    • GNU ELPA is ~450 packages, considered part of Emacs
    • NonGNU ELPA contains third-party packages whose copyright has not been assigned to the Free Software Foundation
    • MELPA for Milkypostman’s Emacs Lisp Package Archive; ~6000 packages that can be freely added

Key Bindings

Here C corresponds to the "Ctrl" key, M the "Meta" one (i.e. "Alt", generally), S to the Shift one, s to the Super one (a.k.a. the infamous Windows/Command key), - is just a separator between a modifier (like Ctrl, Meta, etc.) and an actual key to press while the modifier is still held down. RET means the Enter key, SPC the spacebar, L_ARROW / M-R_ARROW the left / right arrow keys, and U_ARROW / D_ARROW the up / down arrow keys.

For example C-x C-- means: press and hold the "Ctrl" key, and hit the "x" key, then release all, then press and hold the "Ctrl" key, and hit the "-" key, and release all.

At least based on our (Emacs and French keyboard) base settings (i.e. the ones in init-base.el), the following key bindings trigger the corresponding actions:

  • C-a / C-e: move cursor to leftmost / rightmost position
  • C-k: kill all characters on the right from cursor (and thus put them in the kill ring)
  • C-s PATTERN RET / C-r PATTERN RET: perform direct / reverse case-insensitive search of the specified pattern; then each C-s / C-r will jump direct / reverse to any next occurrence; RET will stop the search
  • C-d SEARCH_PATTERN RET REPLACE_PATTERN RET: perform replacements, bound to replace-string (default binding to delete char at cursor - delete-char - not useful enough, as a dedicated key, the Delete one, exists for that)
  • C-l LINE_NUMBER: go to the specified line
  • C-x C-s: save current buffer
  • C-x C-k: kill current buffer
  • C-x C-c: exit Emacs
  • C-g: cancel command/selection
  • C-z: undo last action (or C-x u); to redo, rather than typing C-g C-/ (which would involve a shift, on French keyboards), just perform a non-editing command (such as C-SPC) and then the next C-z commands will go in the opposite direction in the undo chain (they will redo)
  • C-SPC: set the mark (begin selection)
  • C-w: cut selection in the kill ring (selection is thus removed from the current buffer)
  • M-w: copy selection in the kill ring (selection thus remains in the current buffer)
  • C-y: yank (paste from kill ring, replacing any current selection)
  • M-y: replace text just yanked with an earlier batch of killed text
  • C-p: compile, make
  • C-x TAB: indent rigidly, moving the whole selection left/right with M-L_ARROW / M-R_ARROW (see also kill-rectangle)
  • M-< / : M-S-<: go to beginning / end of the current buffer
  • C-x 2: split window horizontally, i.e. top/bottom (split-window-below)
  • C-x 3: split window vertically, i.e. left/right (split-window-right)
  • C-x 0: delete the current window
  • C-x 1: restore a single-window view
  • M-D_ARROW / : M-U__ARROW: scroll down / up in the current buffer
  • M-R_ARROW / : M-L_ARROW: go to next / previous buffer
  • M-q: fill current paragraph (reformat / wordwrap it), i.e. applies fill-paragraph
  • M-m: jump to first non-whitespace in the current line
  • M-x will allow to enter / select commands from the minibuffer (see our useful commands section below)
  • C-o or F8: perform whitespace cleanup (now a built-in package)
  • C-q: go to the next error (next-error)

Additionally, with our complete settings, notably with lsp-mode:

  • s-d: go to definition of word at cursor (lsp-find-definition)
  • s-r: list references to word at cursor (lsp-find-references)
  • s-n: rename symbol globally (lsp-rename)
  • s-q: insert specific character (quoted-insert); for example s-q C-j allows to insert a newline
  • s-c: comment/uncomment the current selection (comment-dwim is a toggle, better than comment-region or uncomment-region)

Frequent Actions

  • to tune the font size:
    • temporarily: use C-x C-+ to increase, C-x C-- to decrease (or press Shift then click the first mouse button to select a relevant option; or, even better, use C-mousewheel)
    • permanently: one may add in one's Emacs configuration file for example: (set-face-attribute 'default nil :height 100)
  • to insert special characters (e.g. tab or newline) as raw characters in commands (e.g. in I-search or replace-string): use for example M-x quoted-insert <tab>, which is bound in our conventions to s-q (instead of C-q, already taken); note that pasting a tab with the mouse in the minibuffer works as well
  • to insert in the current buffer the output of a shell command: C-u then M-!: enter that shell command, whose output will be pasted at the current cursor position
  • to prefix all lines of the selected region: C-x then r then t, then type the prefix then type Enter (useful for example to indent a series of lines)
  • to sort alphabetically the selected region: M-x sort-lines
  • to go to the matching delimiter (parenthesis, bracket, end of word, etc.): to go forward, use C-M-f, and to go backward use C-M-b
  • to re-select a region (e.g. to perform multiple substitutions in a row on the same region): C-x C-x
  • to abort the current entry in the minibuffer: C-g; if a command seems stuck in the minibuffer, it may be a recursive edit (then try C-], i.e. (abort-recursive-edit)), or not the minibuffer but the echo area that should be cleared (then try M-x C-g)
  • to perform replacements based on regular expressions: M-x replace-regexp RET regexp RET newstring RET, with this REGEXP syntax (more information); for example, to remove, in each line, all characters from the first comma: M-x replace-regexp RET ,.* RET , RET
  • to open a file that is very large and/or difficult to parse/display: M-x find-file-literally
  • to describe the action to which a given key corresponds: M-x describe-key
  • to describe the character (including its font) at which the point is: M-x describe-char

Other useful commands to trigger, possibly explicitly with M-x:

  • replace-string SEARCH_PATTERN REPLACEMENT; add M-c to set the case-sensitive flag, i.e. to search for the exact string (even if it is lowercase - otherwise uppercase versions thereof will match); the M-% default shortcut requires a shift on French keyboards
  • query-replace SEARCH_PATTERN REPLACEMENT
  • kill-rectangle (operates on a previous selection)
  • indent-region (C-M-\ difficult on French keyboards)
  • eval-expression prompts in the minibuffer for the (ELISP) expression to evaluate, whose result is briefly displayed there, and recorded in the *Messages* buffer (see this complete guide about ELISP evaluation)

See also our Performing a Merge with Emacs section.

Package Managers

There are at least:

  • package.el
  • straight.el
  • Elpaca: Async Emacs Package Manager (current state of the art, and the one on which we currently rely)

use-package is not a package manager, it is an extensible configuration macro that is specialised by most of the package managers so that it can be used with any.

Refer to this page for a comparison of package managers.

Elisp Hints

Emacs Lisp is a Lisp dialect made for Emacs.

See the GNU Emacs Lisp Reference Manual.

An Emacs init file contains a series of Lisp expressions, each of them consisting of a function name followed by arguments (expressions), all surrounded by parentheses.

For example: (setq fill-column 60) calls the function setq (set quoted) to set the variable fill-column to 60; as setq affects only the current buffer’s local value, in an initialisation file setq-default is generally preferred.

  • boolean values: t stands for "true", and nil for "false"
  • to display a message: (message "Hello world!"); with a variable: (message "My selected font name: %s" my-font-name)
  • a leading single-quote makes a symbol a constant - otherwise it would be treated as a variable name; for example: (setq-default major-mode 'text-mode)

To display messages in standard buffers:

  • a regular message (thus in *Messages*): (message "This is my message.")
  • a warning message (thus in *Warnings*), with a (warning) type specified: (display-warning "foo" "This is my warning."); it displays there: "Warning (foo): This is my warning."

Elisp examples may be the following conditional setting:

(if (boundp 'coding-category-utf-8)
   (set-coding-priority '(coding-category-utf-8)))

Or the next function definition and key binding:

(defun my-split-window-func ()
 (interactive)
 (split-window-below)
 (set-window-buffer (next-window) (other-buffer)))

(global-set-key (kbd "C-x 2") #'my-split-window-func)

If needing to include a configuration file in another:

(load-file "~/elisp/foo.el")

To trigger multiple calls in a single expression, use:

(progn do-this
       do-that)
(defun func (arg1 arg2)
   "Always document your functions."
   <function body>)

(defvar var-name <the value>
   "Always document your variables.")

To concatenate:

  • strings: (concat "foo" "bar")
  • filesystem elements: (file-name-concat "/tmp" "foo") results in "/tmp/foo".

Related Elisp information sources:

Troubleshooting

Handling Errors

Sometimes problems arise due to older packages, for example when a new version of Emacs is used. This may be solved by removing the cache of the package manager (e.g. ~/.emacs.d/straight, ~/.emacs.d/elpaca), relaunching Emacs and waiting for its state (e.g. all related clones) to be downloaded/built again.

To investigate a problem, one may run Emacs with: emacs --debug-init.

Relying a safe, minimal, fallback Emacs

As many software ecosystems, the Emacs one tends to change/break frequently, and then one's init.el cannot be edited anymore with a functional Emacs - and the whole situation quickly degenerates in a mess.

One way of overcoming these issues is to have multiple versions of Emacs' configuration, including a very basic one that is never expected to break - just for the purpose of having at all times a base Emacs to fix the others; this is one of the purposes of our rather minimal init-myriad-base configuration, to be used that way:

$ DIR="${HOME}/.emacs.d/myriad-fallback"
$ mkdir $DIR && cd $DIR
$ ln -s $CEYLAN_MYRIAD/conf/init-myriad-base.el init.el

Then an always-available Emacs may be run with: emacs --init-directory=$DIR, which can made easily available thanks to, in one's shell configuration: alias esafe='emacs --init-directory=${HOME}/.emacs.d/myriad-fallback' (esafe standing for editor safely available).

Alternatively, such a feature can better be implemented thanks to a shell function (to rely as much as possible on a safe emacs, otherwise on gedit, otherwise on nano); see our .bashrc.basics shell file for that.