This is the GNU Emacs configuration file of Eric Haberstroh <[email protected]>.
The entire configuration lives within this Org mode file. On startup,
the actual init file (init.el
) will initialize the package system
and the use-package macro, then extract all the source code blocks
from this file and execute them (i.e. load the rest of the
configuration). Have a look at init.el
to see what’s happening
there.
You can find the source code of this configuration as well as its project history on GitHub. A readable HTML version is stored on Erixpage.de.
This configuration has been tested with GNU Emacs version 26.1 on a 64-bit Ubuntu MATE 18.04 system. Emacs has been compiled with the following commands:
./configure --with-mailutils --with-xwidgets
make
sudo make install
Most of the compilation requirements can be installed as dependencies for building Emacs 25. Some additional libraries and programs have been installed. The following commands should suffice to make compilation of Emacs possible:
sudo apt-get build-dep emacs25
sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libsystemd-dev mailutils
In the following sections of this document, a variety of configuration settings are made that fit my personal taste. While it is certainly possible to use this configuration in its whole, I would encourage you to instead pick the parts of it that fit your personal style.
Questions and comments are welcome at [email protected] or the GitHub issue tracker.
This entire configuration file is licensed under a Creative Commons Attribution 4.0 International license (CC BY 4.0). See that page for more information about your rights.
I do not wish to use Emacs’ built-in customization interface. I would also like to keep my init file clean from its ugly insertions. Therefore let’s define a custom file and then proceed to ignore it forever.
(setq custom-file (concat user-emacs-directory "custom.el"))
Since we’ll be installing a lot of additional minor modes in the course of this configuration, the modeline can get quite overwhelming. Many of the minor modes are active all the time, but I don’t want to know about them; or their modeline strings might be unnecessarily long.
Delight can be used to hide or abbreviate these modeline strings. It can also be used conveniently together with use-package.
(use-package delight)
Some modes are built right into Emacs, or they might come with packages that aren’t installed explicitly but rather as dependencies. We can “delight” these right here at the beginning.
(delight '((auto-revert-mode nil autorevert)))
Instead of cluttering the file system with backup files ending in ~
,
I prefer Emacs to save all backups in a central directory. The
following settings, taking directly from EmacsWiki, accomplishes that.
(setq backup-by-copying t
backup-directory-alist
'(("." . "~/.emacs.d/backup/"))
delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t)
I usually only use one Emacs frame. The title of that frame should therefore just be “Emacs”.
(setq frame-title-format "Emacs")
Disable the ugly tool-bar at the top and the unnecessary scroll-bar at the right edge of the frame. While I seldomly use the menu-bar, it can still be useful sometimes.
(tool-bar-mode -1)
(scroll-bar-mode -1)
I need neither noise nor flashy screen effects from Emacs.
(setq ring-bell-function 'ignore)
By default, Emacs shows a welcome screen on startup. I prefer dashboard which shows some useful lists of files, bookmarks and projects. First, let’s disable the splash screen and set a nicer message for the scratch buffer (I already know what it’s doing, no need to explain it to me).
(setq inhibit-splash-screen t
initial-scratch-message
(concat ";; Welcome to Emacs "
emacs-version
" on "
(system-name)
".\n\n"))
Then let’s install dashboard.
(use-package dashboard
:config
(setq dashboard-startup-banner 'logo)
(dashboard-setup-startup-hook))
By default, Emacs uses the Ubuntu font family on my system. I prefer Source Code Pro, a free Adobe font.
(add-to-list 'default-frame-alist '(font . "Source Code Pro 12"))
The default theme is a little too bright for my taste. Let’s use Zenburn instead.
(use-package zenburn-theme
:config
(load-theme 'zenburn t))
By default, Emacs only displays the current line number in the modeline. I much prefer to see which column I’m in, too.
(column-number-mode t)
Helm, in its own words, “is an Emacs framework for incremental completions and narrowing selections.”
(use-package helm
:delight helm-mode
:bind (("M-x" . helm-M-x)
("C-x C-f" . helm-find-files)
("C-x b" . helm-mini)
("C-x C-b" . helm-buffers-list))
:config
(require 'helm-config)
(helm-mode t))
Which-key is a minor mode for Emacs that displays the key bindings
following your currently entered incomplete command (a prefix) in a
popup. For example, after enabling the minor mode if you enter C-x
and wait for the default of 1 second the minibuffer will expand with
all of the available key bindings that follow C-x
(or as many as
space allows given your settings).
(use-package which-key
:delight which-key-mode
:config
(which-key-mode))
Don’t bother me to type in “yes” or “no” when a simple “y” or “n” should suffice. These aren’t all that close on the keyboard, after all.
(fset 'yes-or-no-p 'y-or-n-p)
Why type parentheses yourself when there is Electric Pair mode? Let’s enable it globally.
(electric-pair-mode t)
Especially in Lisp code, finding the right balance of parentheses is key. This mode helps.
(show-paren-mode t)
By default, bookmarks are saved in a file called
~/.emacs.d/bookmarks
. I want to share bookmarks between machines,
so I’ll put the bookmarks file in my ~/org
directory, which is
synced between my computers.
(setq bookmark-default-file "~/org/bookmarks")
Due to Orgmode opening a lot of files to compute the agenda, the default recent files list is fairly useless to me. Since I can already access my Org index from the bookmarks, I don’t in fact need the Org files in that list at all. So let’s exclude them.
(add-to-list 'recentf-exclude "/org/")
Magit is an interface to the version control system Git, implemented as an Emacs package.
The user manual recommends setting up some keybindings and enabling a global minor mode with some bindings for all file-visiting buffers.
(use-package magit
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch-popup))
:config
(global-magit-file-mode t))
I often need to work on files which are stored on another machine, be
that via SSH or FTP connections. Emacs has a built-in library called
TRAMP which handles these connections. You can also store a list of
passwords for these machines in a file called ~/.authinfo.gpg
, thus
sparing you the hassle of typing them in over and over (and also
remembering them in the first place). In order for this to work with
the FTP method, two variables need to be set which point to the
authinfo file.
(setq auth-sources "~/.authinfo.gpg"
ange-ftp-netrc-filename auth-sources)
Projectile is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies.
(use-package projectile
:delight '(:eval (concat " " (projectile-project-name)))
:config
(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(projectile-mode +1))
Org mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system.
In fact, this whole Emacs configuration file is written in Org mode, because it enables extracting source code blocks from files. The extensive documentation of what a particular setting achieves is thus never far from the actual code, plus you can collapse sections and organize your settings in a far more structured way. In short, I love it.
After we have already added the Org ELPA in the Package system
section, we can now install the org-plus-contrib
package, which
contains the actual Org package as well as some additional goodies.
This does also have the advantage of giving us the latest version of
Org mode as compared to the one that comes packaged with Emacs.
The manual also recommends setting up certain keybindings, so let’s get that done right at the beginning.
(use-package org
:ensure org-plus-contrib
:bind (("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture))
:config (require 'org))
When hitting RET
over a link, I rarely want to split that link into
two lines. Much more often I want to follow the link, so let’s enable
that behaviour.
(setq org-return-follows-link t)
The following function does some preliminary setup I wish to run when
I enter an Org mode file – namely to enable auto-fill-mode
.
(defun eh/setup-org-mode ()
"Setup the editor for Org mode files."
(auto-fill-mode t))
(add-hook 'org-mode-hook 'eh/setup-org-mode)
By default, Org toggles the TODO state of a task between TODO, DONE, and nothing. I would like to have some additional states available:
- WAIT to indicate I’m waiting for something else to happen or someone else to do something in relation to the task
- CANCEL for tasks which I do not intend to pursue further
- DELEG for tasks which I have delegated to someone else and no longer need to pay attention to
When the state of a task changes, I would like to record when that happened in a LOGBOOK drawer (for some of these changes). The following records should be made when a status is set:
- WAIT: Timestamp and a short note to indicate what I’m waiting for
- DONE: Timestamp of when the task was completed
- CANCEL: Timestamp of when the task was cancelled
- DELEG: Timestamp and a short note to indicate who the task was delegated to
Let’s set these states up.
(setq org-log-into-drawer t
org-todo-keywords
'((sequence "TODO(t)" "WAIT(w@)" "|" "DONE(d!)" "CANCEL(c!)" "DELEG(e@)")))
All of my Org mode files, at least those relevant for my agenda, live
in ~/org/
. So the list of agenda files should contain just this
directory, as the manual recommends.
(setq org-agenda-files
(list (expand-file-name "~/org")))
I’d like to be able to move subtrees between all my agenda files. For that purpose, let’s tell Org to consider all agenda files as refile targets and display headings up to level 2.
(setq org-refile-targets
'((org-agenda-files :maxlevel . 2)))
While there are email clients for Emacs and I have tried a few (particularly notmuch), I simply cannot live without Thunderbird. In order to link to specific email messages in Thunderbird from Org files, I have installed a Thunderbird add-on called Thunderlink.
The following code snippet adds a handler to Orgmode so that it can open such messages directly in Thunderbird. I have taken it from this mailinglist thread.
(org-add-link-type "thunderlink" 'org-thunderlink-open)
(defun org-thunderlink-open (path)
"Open a specified email in Thunderbird with the help of the Thunderlink add-on."
(start-process "myname" nil "thunderbird" "-thunderlink" (concat "thunderlink:" path)))
The Elfeed RSS reader is an excellent choice for keeping up with blogs, podcasts, comics, and news sources from within Emacs. I use it together with elfeed-org. The latter enables storing the RSS feeds I’d like to follow in an Org file.
First, let’s pull in Elfeed and elfeed-goodies. This enables some enhancements of the Elfeed interface. I would also like to store the feed database together with my other Org files. Since these are synchronized between machines, I don’t have to bother reading things twice.
(use-package elfeed
:bind (("C-x w" . elfeed))
:config
(setq elfeed-db-directory "~/org/elfeed"))
(use-package elfeed-goodies
:config
(elfeed-goodies/setup))
Then let’s install elfeed-org and set it up to read a list of feeds
from my ~/org/feeds.org
file.
(use-package elfeed-org
:config
(elfeed-org)
(setq rmh-elfeed-org-files (list "~/org/feeds.org")))
The following subsections set up Emacs to support a variety of programming languages and related file formats which I use.
The following setup is largely based on this blog post by Ben Simon.
First, let’s define a function to set up a reasonable environment for PHP coding, including indentation with four spaces (and no TABs!). Since I will be using web-mode for non-PHP files including template files that contain PHP code, php-mode will not need to care about HTML.
We’ll also pull in ac-php for aggressive autocompletion.
(use-package ac-php
:config
(auto-complete-mode t)
(require 'ac-php)
(setq ac-sources '(ac-source-php))
(yas-global-mode t)
(ac-php-core-eldoc-setup))
(defun eh/setup-php-mode ()
"Set up indentation and other bits and pieces for PHP files."
(setq indent-tabs-mode nil
c-basic-offset 4
php-template-compatibility nil)
(subword-mode t))
Then, let’s install php-mode.
(use-package php-mode
:config
(require 'php-ext)
(add-hook 'php-mode-hook 'eh/setup-php-mode))
Templates, CSS files and other related web files will be excellently handled by web-mode.
Again, let’s define a setup function.
(defun eh/setup-web-mode ()
"Set up indentation and other bits and pieces for web-mode."
(setq indent-tabs-mode nil
web-mode-markup-indent-offset 4
web-mode-css-indent-offset 4
web-mode-code-indent-offset 4)
(add-to-list 'auto-mode-alist
'("\\.tpl\\'" . web-mode)))
Then let’s pull in the package.
(use-package web-mode
:config
(add-hook 'web-mode-hook 'eh/setup-web-mode))
Some settings may need to reside in a private file that is kept
outside source control. The constant private-file
is defined to
contain the path to such a file. If it exists, it will be loaded at
the end of the startup process.
(defconst private-file (concat user-emacs-directory "private.el")
"A private initialization file that is kept outside of source
control and is loaded at the very end of the startup process.")
(when (file-readable-p private-file)
(load-file private-file))