Skip to content

Latest commit

 

History

History
528 lines (425 loc) · 17.8 KB

config.org

File metadata and controls

528 lines (425 loc) · 17.8 KB

Emacs Configuration

Introduction

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.

License

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.

https://i.creativecommons.org/l/by/4.0/88x31.png

Disable the customization system

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"))

Delight modes

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)))

Backups

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)

Interface

Change frame title

I usually only use one Emacs frame. The title of that frame should therefore just be “Emacs”.

(setq frame-title-format "Emacs")

Disable tool-bar and scroll-bar

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)

Disable the bell

I need neither noise nor flashy screen effects from Emacs.

(setq ring-bell-function 'ignore)

Inhibit splash screen and show dashboard

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))

Theme and font

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))

Show column number in modeline

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

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

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))

Yes or No questions

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)

Editing

Electric pairs

Why type parentheses yourself when there is Electric Pair mode? Let’s enable it globally.

(electric-pair-mode t)

Highlight matching parens

Especially in Lisp code, finding the right balance of parentheses is key. This mode helps.

(show-paren-mode t)

Bookmarks

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")

Recent files

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/")

Source control

Magit

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))

Remote connections

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)

Project management

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

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)

Todo keywords and logging

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@)")))

Agenda

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")))

Refiling

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)))

Linking to Thunderbird messages

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)))

RSS reader

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")))

Programming

The following subsections set up Emacs to support a variety of programming languages and related file formats which I use.

PHP

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))

Load a private configuration file

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))