Emacs Tutorial

2024-10-03

There are many tutorials available but this one is mine where I cover sensible defaults to showcase the standard Emacs experience.

My goal is to guide you through setting up an IDE similar to VSCode from the ground up. I will also demonstrate how to use Emacs as a complete integrated computing environment, allowing you to read news, send emails, play media, and much more!

Info

This is a work in progress: my plan is to record a screencast that covers the entire content. If you encounter any issues, please let me know; I’m committed to keeping this document updated.

This file is licensed under a free/libre copyleft license (GPL or CC BY-SA).

Changelog

  • 2024-10-07: explained the Compile workflow.
  • 2024-10-05: added the Development section.

In this tutorial, I will list all the commands, key bindings, and settings to provide a comprehensive reference documentation for power users. This tutorial is based on Emacs version 29, which is a modern release that works exceptionally well out of the box.

If you are new to Emacs, do not read this in one sitting; take your time and don’t panic; you will be here for the long-term. Feel free to modify the configuration to your liking. Good luck!

Context

To put things into perspective, Emacs started in 1976 as a set of macros for the Tape Editor and Corrector (TECO). GNU Emacs began in 1984 as a true Lisp interpreter, and it is among the oldest free and open-source projects still under development.

Emacs helps you be productive by offering an integrated environment for a wide range of tasks. This tool has been tested and proven to work well.

First contact

In this first session, we will learn the most basic usage.

Install

Emacs is available on every plateform. Get it with your package manager, for example, by running dnf install -y emacs-nox. This is the lightweight terminal version; nox means no X, which used to be a display server name. Later, we’ll use the full version for multimedias.

Start

Start Emacs in the terminal like this: emacs -nw. You can ensure a clean start using the -Q option.

Emacs keybindings use the alt and ctrl modifiers like this:

  • M-x means press alt+x. M stands for meta, and it is the alt key on PC keyboards.
  • C-x 3 means press ctrl+x, release ctrl then press 3.
  • C-h C-q means press ctrl+h then ctrl+q. You can also maintain ctrl while pressing h then q.

When you are stuck, or if you want to exit a menu, hit C-g repeatedly to stop what Emacs is doing. If you ever need to quit Emacs, hit C-x C-c, but you shouldn’t do that :).

After starting Emacs, run the help-quick command by pressing C-h C-q; your terminal will look like this:

emacs-tut-quick-help

At the bottom, you now have a helpful quick help window that shows you the essential commands. Once you are comfortable, close the help window by running the same command again.

Here are the only keys you absolutely need to know:

  • M-x: (alt+x) to run a command, and
  • C-g: (ctrl+g) to cancel a command.

Cursor movements

This section introduces how to move the cursor, which is also called the point.

Here are the main cursor movements:

KeyCommandDescription
C-a or HOMEmove-beginning-of-lineMove point to visible beginning of current logical line.
C-e or ENDmove-end-of-lineMove point to end of current line as displayed.
C-f or forward-charMove forward to the next character.
M-f or ctrl+forward-wordMove forward to the next word.
C-b or backward-charMove backward to the previous character.
M-b or ctrl+backward-wordMove backward to the previous word.
C-p or previous-lineMove vertically up
M-{backward-paragraphMove backward to start of paragraph.
C-n or next-lineMove vertically down
M-}forward-paragraphMove forward to end of paragraph.
C-M-fforward-sexpMove forward across one balanced expression.
C-M-bbackward-sexpMove backward across one balanced expression.
M->end-of-bufferMove point to the end of the buffer.
M-<beginning-of-bufferMove point to the beginning of the buffer.
C-v or PageDownscroll-up-commandScroll text of selected window upward.
M-v or PageUpscroll-down-commandScroll text of selected window down.
C-lrecenter-top-bottomSuccessive invocation recenter the window.
M-g ggoto-lineGo to LINE.
M-g cgoto-charGo to POSITION.
M-g iimenuGo to a place chosen using a buffer menu.
C-x C-@pop-global-markGo to the last point position.

Note that these keys mostly work by default with readline (e.g. in bash).

This covers most cursor movements, and with little practice, you will memorize the commands. Notice how ctrl is used for short movements while alt makes longer movements.

Tip

C-M-b (backward-sexp) is not restricted to parenthesis (; use it to find matching [, { or " too.

Tip

Press C-l twice to scroll the buffer and move the cursor to the top. That’s useful to compare two buffers by matching their lines vertically.

Checkout the M-x help-with-tutorial to get some practice.

Window navigation

This section introduces how to manage the window layout.

KeyCommandDescription
C-x 1delete-other-windowsMake WINDOW fill its frame.
C-x 2split-window-belowSplit WINDOW into two windows, one above the other.
C-x 3split-window-rightSplit WINDOW into two side-by-side windows.
C-x 0delete-windowDelete WINDOW.
C-x oother-windowSelect another window in cyclic ordering of windows.
C-x bswitch-to-bufferDisplay buffer in the selected window.
C-x +balance-windowsBalance the sizes of windows shown.
Tip

Use balance-window when you have more than 2 splits.

To move between windows, run M-x windmove-default-keybindings to use shift+arrows for moving the cursor to another window:

KeyCommandDescription
shift+windmove-leftMove to the left WINDOW.
shift+windmove-upMove to the up WINDOW.
shift+windmove-downMove to the down WINDOW.
shift+windmove-rightMove to the right WINDOW.

File

This section introduces how to open and save a file.

KeyCommandDescription
C-x C-ffind-fileEdit file FILENAME.
C-x C-ssave-bufferSave current buffer in visited file if modified.
C-x C-wwrite-fileWrite current buffer into file FILENAME.
C-x kkill-bufferKill the buffer specified by BUFFER.
C-x C-qread-only-modeToggle RO mode.

If you open a directory instead of a file, Emacs lists the directory contents in a special buffer named dired with the following commands:

KeyCommandDescription
RETdired-find-fileOpen the file or directory at point.
Rdired-do-renameRename current file.
sdired-sort-toggle-or-editToggle sorting by date.
ddired-flag-file-deletionMark a file for deletion.
xdired-do-flagged-deleteDelete the marked files.
(dired-hide-details-modeToggle visibility of detailed information.
grevert-bufferRefresh the buffer.
Tip

Dired is a powerful file manager, we’ll learn more about it later.

Modes

Every buffer is associated with a mode, which alters certain behaviors, key bindings, and text display in that buffer. The idea is to customize the appearance and features available based on the contents of the buffer. The current modes are displayed at the bottom of the buffer in the modeline. Run the M-x command named after the mode to manually toggle its usage.

Emacs has built-in support for many file types, for example, if you open a file named test.css and write color: pink, then the buffer will look like this:

emacs-tut-css

The mode command lets you toggle the mode, for example you can disable the highlighting with M-x css-mode. You can also remove all modes by activating M-x fundamental-mode.

Edition

Selection happens between a mark and the point. Here are the main editing keys:

KeyCommandDescription
C-SPCset-mark-commandSet the mark where point is, and activate it.
M-wkill-ring-saveSave (“copy”) text between point and mark.
C-wkill-regionKill (“cut”) text between point and mark.
C-yyankReinsert (“paste”) the last stretch of killed text.
C-kkill-lineKill the rest of the current line.
M-DELbackward-kill-wordKill previous word.
M-hmark-paragraphPut point at beginning of this paragraph, mark at end.
C-x hmark-whole-bufferMake region contain the entire buffer (“Select all”)
C-/ or C-_undoUndo some previous changes.
C-M-_undo-redoUndo the last undo.
Tip

Use M-x insert-char to insert special characters like emojis.

To search for text:

KeyCommandDescription
C-sisearch-forwardDo incremental search forward.
C-risearch-backwardDo incremental search backward.
Tip

Press the search key again to go to the next match.

To replace text:

KeyCommandDescription
M-%query-replaceReplace some occurrences of STRING.
C-M-%query-replace-regexpReplace some things after point matching REGEXP.

Once Emacs finds a match, press:

  • y to replace
  • n to skip
  • ! to do all replacement without asking.
  • ctrl+g to cancel.

At this point, your terminal may look like this:

emacs-tut-dired

Customization

In this second session we learn how to customize Emacs behaviors and set up some quality-of-life improvements.

Theme

Setup color theme with M-x load-theme:

  • modus-vivendi for dark.
  • modus-operandi for light.

These are highly accessible themes by @protesilaos, conforming to the highest standards for colour contrast between background and foreground values (WCAG AAA).

Tip

If the colors are off, make sure to set the TERM variable, for example start emacs with TERM=xterm-256color emacs in tmux

For comparison, Emacs now looks like this:

emacs-tut-modus

History

Emacs can remember what you do to help recall past actions:

  • M-x savehist-mode saves the command history. That way, pressing M-x shows the last used commands.
  • M-x save-place-mode saves the location of the point when you kill a buffer and returns to it the next time you visit the associated file.
  • M-x recentf-mode saves the recently opened files
  • M-x winner-mode records the changes in window configuration so that you can revert any layout change with M-x winner-undo, for example after running delete-other-windows by mistake.

Lisp Config

Emacs customization is written in the Lisp programing language. In fact, about 70% of Emacs is written in Lisp, only the bare interface for the operating system is written in C. Here is a primer on the basic syntax:

  • Comments start with: ;;.
  • Call a function (e.g. command) with: (function-name arg1 arg2).
  • True and False are t and nil.
  • Symbols are prefixed with ', like 'utf-8.
  • List can be written as: (list 1 2 3), or with the quote syntax: '(1 2 3).
  • Pairs can be written as: (cons 42 23), or with the dot syntax: (42 . 23).

In the scratch buffer, write:

;; Obligatory hello world
(message "Hello %s" 'emacs)

Here are useful commands to work with Lisp:

KeyCommandDescription
C-x C-eeval-last-sexpEvaluate sexp before point.
M-:eval-expressionEvaluate EXP and print the value in the echo area.
eval-bufferExecute the current buffer as Lisp code.

dot emacs

Add the following to your ~/.emacs file to ensure the settings persist across restarts:

;; Setup a nice theme.
(load-theme 'modus-vivendi)

;; Use shift + arrow keys to change window.
(windmove-default-keybindings)

;; Record window configuration and enable
;; `M-x winner-undo` command to undo layout changes.
(winner-mode)

;; Remember commands and files for easy access.
(savehist-mode)
(save-place-mode)
(recentf-mode)

Run M-x eval-buffer to apply the settings immediately.

Settings

Settings are defined as custom variables, check out the M-x customize family of commands to set the options interactively.

To change a setting, use the setq command, here are a couple of better defaults:

;; Keep auto-save and backup files in one flat directory
;; (instead of next to the original files)
(setq backup-directory-alist '(("." . "~/.emacs.d/backups/")))

;; Store custom variables in ~/.emacs.d/custom.el (instead of ~/.emacs)
(setq custom-file (locate-user-emacs-file "custom.el"))
Tip

Some settings might be overridden after the init, for example indicate-buffer-boundaries can be reset. In that case, try setq-default instead. (Let me know if you have a better explanation or how to avoid that quirk)

When using the interactive M-x customize-variable command, clicking Save will store the value into ~/.emacs.d/custom.el using this special syntax:

(custom-set-variables
 '(require-final-newline t)
 '(load-prefer-newer t)
 '(tab-width 4))

To move the customization into your ~/.emacs, convert the file like this:

(setq require-final-newline t)
(setq load-prefer-newer t)
(setq tab-width 4)

Key Bindings

To change a key binding, use the global-set-key command, here is a safe change:

;; Do not ask for permission to kill a buffer (unless it is modified)
(global-set-key (kbd "C-x k") 'kill-current-buffer)
Tip

Check out the better-defaults for other safe examples.

Uniquify

When opening two files with the same name, like package.json, it can be confusing to tell their buffers apart. Use uniquify to disambiguate the buffer names, it will rename the buffers with the parent directory when needed:

;; Ensure buffer names are unique
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

package-install

Run M-x package-install to install plugins for languages syntax highlighting. The plugins are usually named language-mode, for example run:

  • M-x package-install markdown-mode

Now, opening a markdown file highlights the syntax. Here are a few more plugins to get started: haskell-mode, rust-mode and yaml-mode.

Vert&co

In this section, we set up a completion framework to drastically improve the M-x and similar actions. By default, Emacs comes with ido, but we’ll use the modern implementation called Vert&co. Get started with the following commands:

  • M-x package-install vertico
  • M-x vertico-mode
  • M-x package-install orderless
  • M-x eval-expression (setq completion-styles '(orderless basic))

This enables two key features:

  • Prompts show available choices in a vertical buffer.
  • Completion is now fuzzy; for example, typing file find will select find-file.

Here is the result (with the nano-emacs theme):

vertico

Then install consult for a better switch-to-buffer command:

  • M-x package-install consult

Add the following to your ~/.emacs:

;; Setup completion framework
(vertico-mode)
(setq completion-styles '(orderless basic))
(global-set-key (kbd "C-x b") 'consult-buffer)

Check out my From Ivy To Vert&co post for more details.

Warning

With vertico, you might have to use M-RET to submit the minibuffer verbatim. This can be necessary because RET will pick the current selection, which prevents creating a new file matching an existing selection, for example, to pick tut.md when there is a matching tutorial.md.

Bookmarks

Save interesting locations with bookmarks:

CommandDescription
bookmark-setSet a bookmark named NAME at the current location.
bookmark-jumpJump to bookmark BOOKMARK (a point in some file).
bookmark-deleteDelete BOOKMARK-NAME from the bookmark list.
Tip

Bookmarks work with most modes, and as we’ll see later, they can also be used for remote tramp locations, and eww web pages. consult-buffer offers bookmark access by default.


You now have a fully functional environment. The next section introduces how to learn on your own before we dive in more advanced concepts.

Learn

In this session we learn how to learn within Emacs.

Describe

Run the following commands to access the documentation and the source of every Emacs feature:

KeyCommandDescription
C-h fdescribe-functionDisplay the full documentation of FUNCTION (a symbol).
C-h vdescribe-variableDisplay the full documentation of VARIABLE (a symbol).
C-h mdescribe-modeDisplay documentation of current major mode and minor modes.
C-h bdescribe-bindingsDisplay a buffer showing a list of all defined keys.
C-h kdescribe-keyDisplay documentation of the function invoked by KEY-LIST.
Tip

Use C-h f to read a command’s documentation.

Which Keys

Install the which-key package to get a tooltip about the keys that complete a sequence:

  • M-x package-install which-key
  • M-x which-key-mode

Now try pressing C-h. After a short delay, the list of all available commands will be displayed at the bottom.

Tip

Enable which-key-mode to discover available commands.

Manuals

Read the info pages by running M-x info. In the info mode:

KeyCommandDescription
mInfo-menuThe list of current nodes
]Info-forward-nodeGo to the next page.
[Info-backward-nodeGo backward one node.
uInfo-upGo to the superior node of this node.
nInfo-nextGo to the “next” node, staying on the same hierarchical level.
tInfo-top-nodeGo to the Top node of this file.
dInfo-directoryGo to the Info directory node.
M-nclone-bufferCreate and return a twin copy of the current buffer.
Tip

Run M-x clone-buffer to persist the buffers that gets auto-replaced, like Help or Describe, that way you can accumulate multiple instances.

To search the info pages, use M-x consult-info.

Read the Un*x manual by running M-x man.

Info

The manuals are the ultimate references (after the source). Use them!

System

In this session we learn how to perform system tasks.

Process

Run M-x proced to list the system processes:

KeyCommandDescription
s Sproced-sort-interactiveSort Proced buffer.
Tproced-toggle-treeToggle the display of the process listing as process tree.
mproced-markMark a process.
kproced-send-signalSend signals to marked processes.
fproced-filterFilter process.
Fproced-formatChange formatting.
grevert-bufferRefresh the buffer.

Run M-x list-processes to list child processes and M-x list-timers to list internal tasks.

Commands

Run standalone shell commands:

KeyCommandDescription
M-!shell-commandExecute COMMAND in inferior shell
M-&async-shell-commandExecute COMMAND asynchronously in background.
M-|shell-command-on-regionExecute COMMAND in inferior shell with region as input.

For example, type M-! uptime to display the age of your host to the minibuffer. The output is also copied to the *Messages* buffer.

Tip

Prefer async commands to avoid locking your session, for example, connect to a local server with:

M-& xdg-open http://127.0.0.1:9001

The input/output will be available in the *Async Shell Command* buffer.

You can adjust the process environment variables with the M-x setenv command. Note that Emacs uses the exec-path variable to discover commands, so you might want to add your own program locations like this:

;; Ensure local scripts are available.
(add-to-list 'exec-path (concat (getenv "HOME") "/.local/bin"))

Shell

Start a shell session with M-x shell to create a dumb terminal for running bash. This works similar to a regular terminal, but you have to press M-p to access previous commands. If needed, see the vterm package for a full terminal emulation.

Tip

Use C-u M-x shell to start a secondary shell by using a different buffer name.

There is also eshell, which is an advanced mode that lets you run lisp command directly. Though I don’t personally use eshell.

Development

In this session we learn how to write software using Emacs.

Project.el

Emacs provides a generic framework for managing projects. This feature is also provided by an external package named projectile, but the core capability is now built in Emacs through project.el.

Here are the project commands:

KeyCommandDescription
C-x p pproject-switch-projectOpen a project.
C-x p fproject-find-fileOpen a file in the current project.
C-x p rproject-query-replace-regexpQuery-replace REGEXP in all the files of the project.
project-forget-projectRemove directory PROJECT-ROOT from the project list.

Compile

Emacs comes with a simple yet powerful compilation mode that operates as follows:

CommandDescription
project-compileRun compile in the project root.
project-recompileRestart the compilation process.
next-errorjumps to the location of the next error.

These commands are not bound by default, but you should set up a key binding for quick access. I configured mine like this:

;; Press F5 to start compilation.
(global-set-key (kbd "<f5>") 'project-compile)

;; Press F3 to jump to the next error.
(global-set-key (kbd "<f3>") 'next-error)

;; Then re-run the compilation with Shift + F5 (to skip the command prompt)
(global-set-key (kbd "S-<f5>") 'project-recompile)
Tip

The compile workflow is the ideal feedback loop for fixing compilation errors. You can use it with any command that outputs file locations, such as path:line: message. Emacs will let you go through all the errors with ease.

Corfu

Corfu enhances in-buffer completion with a small popup. While an older package named company also provides in-buffer completion, Corfu is a better choice since it integrates seamlessly with the Vert&co ecosystem, as it is developed by the same community. For file path completion, we will also utilize the cape package alongside Corfu.

To install Corfu, run the following commands:

  • M-x package-install corfu
  • M-x package-install corfu-terminal
  • M-x package-install cape

Next, add the following to your ~/.emacs:

;; Enable indentation and completion using the TAB key.
(setq tab-always-indent 'complete)

;; Make the completion suggest file paths.
(add-hook 'completion-at-point-functions #'cape-file)

;; Activate in buffer completion everywhere.
(global-corfu-mode)

;; enable corfu in terminal.
;; This is needed until child frame support for terminal Emacs arrives.
(unless (display-graphic-p) (corfu-terminal-mode +1))

Here is an example corfu usage to complete a path with orderless selection:

emacs-tut-corfu

Once the Corfu menu is open, you can:

  • Keep on typing to narrow the selection, and/or
  • Use the arrow keys or M-n to select an entry.
  • Once a single choice is available, pressing TAB will insert the completion.
  • Pressing C-g at any time will cancel the menu, as usual.

Completion can occur in two ways: manual or automatic. I will describe the pros and cons of both solutions, they are equally valid. However, I find that the manual setup is easier to get started.

Manual completion

Press TAB to manually trigger the completion. To use SPC for separating multiple orderless patterns (as you do in the minibuffer), you need to configure this key binding:

;; For manual corfu, use SPC to add orderless separator.
(keymap-set corfu-map "SPC"  'corfu-insert-separator)
Tip

Some modes might still insert a TAB when trying to complete. In that case, use M-TAB, that should always work.

For reference, the example usage screenshot was produced by typing:
"./ TAB png SPC logo

Automatic completion

You can make the completion menu appear automatically after a short delay with:

;; show completion automatically after a short delay
(setq corfu-auto t)

In this situation, to use orderless with corfu, we need a way to insert a match separator. Unlike the minibuffer, SPC interupts corfu to prevent misfires. Therefore, Corfu implements a custom key for in-buffer separator, which is set to M-SPC by default.

For reference, the example usage screenshot was produced by typing:
"./ pause png M-SPC logo.

Unfortunately, M-SPC conflicts with the GNOME Shell binding for window menu. Unless you need this GNOME key, you can disable it by running this shell command in bash:

# Disable alt-spc for Corfu... The menu is still available with WIN+right-click.
gsettings set org.gnome.desktop.wm.keybindings activate-window-menu ['']

Alternatively, you can bind a different key for the corfu-insert-separator command or simply use the manual completion, which is less problematic overall.

Prog Mode

Common modes for source code inherit from prog-mode, which can be used to define general behaviors. For example, you can make the word motions handle camelCase boundaries by enabling the subword-mode:

;; This mode changes the definition of a word boundary so that word commands
;; stop at "Gtk" and "Window" in "GtkWindow"
(add-hook 'prog-mode-hook 'subword-mode)

Here are some useful prog-mode commands:

KeyCommandDescription
C-x C-;comment-lineComment or uncomment current line.

Flymake

Flymake is a minor Emacs mode for performing on-the-fly syntax checks. It reports errors using squigglies under the offending source code. Here are the Flymake commands:

CommandDescription
flymake-modeToggle Flymake mode on or off.
flymake-goto-next-errorJump to the next error.
flymake-show-buffer-diagnosticsShow the current buffer’s diagnostics.
flymake-show-project-diagnosticsShow the current project’s diagnostics.

Here is an example configuration:

;; Activate flymake for every prog-mode buffers.
(add-hook 'prog-mode-hook 'flymake-mode)

;; Use F3 to jump to the next error.
(global-set-key (kbd "<f3>") 'flymake-goto-next-error)
Tip

Run flymake on your ~/.emacs to see the suggestions. We’ll address them in the use-package section below.

Flymake works standalone using backend functions that are usually provided by file modes. For example python-mode uses pyflakes by default. When using the language server client eglot, Flymake will use that as an additional back-end.

Language server

Emacs comes with a language server client called eglot, which functions as follows:

CommandDescription
eglotStart the language server.
eglot-shutdownKill the server.
eglot-code-actionsExecute server actions.
xref-find-definitionsFind definition.
xref-find-referencesFind call sites.

The current file mode typically configures the relevant server in the eglot-server-programs list. If it’s not configured, eglot will prompt you for the program or network endpoint to use.

Tip

The server logs are available in a buffer named *EGLOT (mode) events*

Eglot works seamlessly out of the box, requiring no additional configuration or external packages. It integrates with existing Emacs features like Flymake and Xref.

Magit

Magit is the user interface for the Git revision control system.

Setup

Magit is not available on the default ELPA package registry, so you need to set up the MELPA registry. Add the following to your ~/.emacs:

;; Add MELPA registry for Magit.
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)

After inserting the above snippet, run M-x eval-buffer, or simply C-x C-e to set the package-archives value.

Then run the following commands:

  • M-x package-refresh-contents
  • M-x package-install magit

Finally, add the following to your ~/.emacs to bind the main command:

;; Quick access to Magit.
(global-set-key (kbd "C-x g") 'magit-status)

Usage

Inside a repository, run M-x magit-status to get the Magit interface. Here are the main keys:

  • TAB: Expand/Collapse a section.
  • RET: Visit a thing. When the cursor is on a diff, this creates a temporary buffers (press q to close it); ctrl+j visits the real file.
  • j: Jump to a section.
  • ?: View the command list.
  • $: View the actual Git commands that Magit is performing.

To prepare a commit, on a chunk or a file, press:

  • s: Stage
  • u: Unstage
  • k: Trash

Here are the main git commands:

  • b: branch
  • c: commit
  • P: push
  • f: fetch
  • F: pull
  • l: log
  • M: remote
  • A: cherry-pick

Magit interface doesn’t use modifiers like ctrl or alt.

Example git commands

After selecting a command, a new buffer appears to let you toggle options. The argument can be set vertabim, for example by pressing - followed by the flag, like v.

Here are some example workflows:

  • Push with lease: P -> -f -> u
  • Commit amend and reset the author: c -> -R -> a

Rewrite history

To start a local rebase, place the cursor on a commit (either in the status page or in the log view) and press r followed by i. A rebase buffer will appear with the list of commits:

  • alt+p/n: Reorder a commit.
  • ctrl+k: Drop a commit.
  • e: Edit a commit.
  • r: Edit a commit message.
  • s/f: Squash or fixup a commit.

Once you are done, C-c C-c to apply the changes, or C-c C-k to cancel.

Handle conflicts

When there is a conflict, press e to start an ediff session. In graphic mode, the control window pops up in a new frame, which is not convenient. Set the following setting to display the ediff control within your existing frame:

;; Show the ediff control window inside the current frame, don't create a new window.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)

Here are the commands to handle conflicts:

  • n/p: Go to the next/previous conflict.
  • a/b: Pick the left or right change. You can also manually fix the edits in the bottom window.
  • q: Quit ediff and apply the resolution.

Blame

When viewing a file, run M-x magit-blame then press b:

  • : Open a commit.
  • C-c C-q: Quit the blame mode (or just re-run M-x magit-blame and press q)
Tip

Check out the documentation to learn more: https://magit.vc/


You now have a fully functional integrated developer environment (IDE). The next section introduces how to write source code in different languages.

Languages

In this session we learn how to leverage the programing language modes.

Pretty Print

  • json-pretty-print and json-pretty-print-buffer

Haskell

  • GHCi

Markdown

Press TAB to create tables.

Rust

rustfmt on save

Python

  • M-x run-python
  • M-x python-shell-send-buffer

Advanced

In this session, we will learn some advanced features.

local lisp

  • TODO: show how to install git-clone.el.

server

Enable sub commands like git commit or kubectl edit to open a new buffer within your existing session:

;; Allow this Emacs process to be a server for client processes.
(server-start)

;; Ensure child-process uses the main Emacs to edit files.
(setenv "EDITOR" "emacsclient")

use-package

use-package lets you maintain a portable configuration. Until now, we have installed package interactively, but that’s an issue when you copy your config to a fresh environment because the commands and settings won’t be available.

Instead, you need to leverage the use-package command to manage external packages. The basic syntax looks like this:

(use-package the-package-name
  :ensure t ;; install if needed
  :config
  (setq the-package-option 'value)
  (global-set-key (kbd "C-x g") 'the-package-command))

use-package lets you further declare your config, for example like this:

(use-package the-package-name
  :if (display-graphic-p)
  :diminish
  :custom
  (the-package-option 'value)
  :bind ("C-x g" . the-package-command))

… which is equivalent to:

(when (display-graphic-p)
  (require 'the-package-name)
  (diminish 'the-package-name)
  (setq the-package-option 'value)
  (global-set-key (kbd "C-x g") 'the-package-command))
Tip

Check out diminish to clean up your modeline with use-package, and stick to setq and global-set-key if you prefer.

stow

Use stow to archive your config. Quit emacs now and run the following commands:

# Move the state to XDG location.
mv ~/.emacs.d ~/.config/emacs

# Setup your stow registry:
mkdir -p ~/src/my-dot-files/home/.config/emacs

# Move the .emacs to init.el
mv ~/.emacs ~/src/my-dot-files/home/.config/emacs/init.el

# Install your home package
stow -v --no-folding -d ~/src/my-dot-files -t ~ home
Tip

Use --no-folding to ensure the emacs directory stays in your home, only the init.el will be symlinked.

Keep the general purpose settings in your home stow package, Then you can configure extra features like emails or feeds in dedicated packages.

Tab Bar

Dired

Multi Cursors

Set up the multiple-cursors package to enable editing multiple lines at once:

(use-package multiple-cursors
  :bind
  (("C->" . 'mc/mark-next-like-this)
   ("C-<" . 'mc/mark-previous-like-this)))

Press ctrl+> to create multiple cursors. Then edit as usual and complete with ctrl+g

ELisp

  • TODO: explain how to write custom commands…

Templates

Configure custom abbreviations to help you expand repetitive content. While you can use the builtin dabbrev package, here is a more powerful solution named tempel:

(use-package tempel
  :bind ("M-*" . tempel-insert)
  :init
  ;; Setup completion at point
  (defun tempel-setup-capf ()
    ;; Add the Tempel Capf to `completion-at-point-functions'.
    (setq-local completion-at-point-functions
                (cons #'tempel-expand
                      completion-at-point-functions)))

  (add-hook 'conf-mode-hook 'tempel-setup-capf)
  (add-hook 'prog-mode-hook 'tempel-setup-capf)
  (add-hook 'text-mode-hook 'tempel-setup-capf))

Setup your templates in ~/.config/emacs/templates:

;; ~/.config/emacs/templates
;; https://github.com/minad/tempel#template-syntax

fundamental-mode

(today (format-time-string "%Y-%m-%d"))
(copyr "Copyright © " (format-time-string "%Y ") user-full-name n)

markdown-mode

(kbd "<kbd>" r "</kbd>")
(code "```" r n "```")

Here is how to insert templates:

  • Type today then press TAB to insert the current date.
  • Select some text, then press M-* to apply a template like kbd.

Embark

Extra

In this session we will learn extra things you can do with Emacs.

Micro Features

Emacs contains hundreds of microscopic quality of life features:

  • count-words
  • sort-lines
  • fill-paragraph
  • toggle-truncate-lines

ispell

org mode

notmuch

dired

elfeed

eww

erc

ready-player

vterm

Tramp

;; Transparent Remote Access, Multiple Protocol
(use-package tramp
  :custom
  ;; Ensure multi-hop stays verbatim, e.g. /ssh:user@host|sudo:host:/path
  ;; Without this setting, the bookmark will be reduced to =/ssh:root@host/=, which doesn't work
  ;; Q: is this worth reporting/fixing upstream?
  (tramp-show-ad-hoc-proxies t))

TODO: configure consult to disable remote file preview

Next

Here are further resources to continue your journey:

#emacs