My Emacs configuration
1. What's this?
This page contains my literate Emacs configuration. I hope you'll find some useful snippets here!
You can find all of my configuration files on this Codeberg repository.
2. Setting up package archives
Let's set up some archives from which we can download and install packages.
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/"))
(add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))
(add-to-list 'package-archives '("elpa-devel" . "https://elpa.gnu.org/devel/"))
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
Using the package-refresh-contents
function, we'll get the latest descriptions of the packages that are available from the archives. The optional argument t
ensures that the function is executed asynchronously. Running in the background, it won't lock up Emacs while the package list is being refreshed. You can also refresh the package list manually by running M-x package-refresh-contents.
;; Download descriptions of packages available from the package archives.
(package-refresh-contents t)
3. General ease of use
3.1. Starting up in fullscreen mode
There's no actual fullscreen mode in Emacs, but you get the idea.
;; Fullscreen on start up.
(add-to-list 'default-frame-alist '(fullscreen . fullscreen))
If fullscreen is too much, and you prefer to have Emacs starting up maximized, use this instead:
;; Start up maximized.
(add-to-list 'default-frame-alist '(fullscreen . maximized))
3.2. Visual line mode
Enable visual line based editing (in all types of buffers). This ensures that 'word-wrap' is turned on, and that simple editing commands will act on visual lines, not on logical lines.
;; Enable visual line based editing & word wrapping.
(global-visual-line-mode t)
3.3. Zooming in and out
Let's make zooming in and out a little easier.
;; Zoom in and out like we do in most other programs.
(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
;; Use CTRL plus the track pad (move two fingers up/down),
;; or the mouse wheel, for zooming in/out.
(global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)
(global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease)
3.4. The Tab key and indentation
Tab should try to indent, and if it can't for some reason, it should try to complete stuff (auto-completion). Instead of tabs, I prefer to use spaces for indentation.
;; Try to indent, otherwise complete.
(setq tab-always-indent 'complete)
;; Use spaces instead of tabs for indentation.
(setq-default indent-tabs-mode nil)
3.5. Smooth scrolling
The pixel-scroll-precision-mode is a global minor mode that allows to scroll the display precisely, according to the turning of the mouse wheel.
;; Precise scrolling.
(pixel-scroll-precision-mode)
I don't want scrolling speed to increase progressively when I move the mouse wheel faster.
;; Keep scrolling speed proportional to the mouse wheel speed.
;; If non-nil, moving the wheel faster will make scrolling
;; progressively faster.
(setq mouse-wheel-progressive-speed nil)
3.6. Ensuring that we don't lose our work
3.6.1. Cutting, copying and pasting
By default, Emacs uses 'C-w' to cut, 'M-w' to copy, 'C-y' to paste and 'C-/' to undo. Once you've gotten used to these shortcuts and they're in your muscle memory, you'll run the risk of using them in other applications too. That may cause trouble.
Imagine, for example, that you're writing an email in your browser. You want to cut a line of text, so your Emacs muscle memory kicks in and you're pressing C-w. Congratulations, you have just closed your browser window!
For this reason, I prefer using the common keyboard shortcuts for cutting, copying, pasting and undoing: C-x, C-c, C-v and C-z. You can use M-x cua-mode to toggle these key bindings: This command sets up key bindings that are compatible with the Common User Access (CUA) system used in many other applications. Keep in mind, however, that Emacs' default undo behavior deviates from what you're probably used to from other editors).
;; Cut, copy and paste like we do in most other programs.
(cua-mode 1)
3.6.2. Confirm exiting Emacs
By default, C-c C-x closes Emacs immediately. Let's have Emacs ask for confirmation before exiting.
(setq confirm-kill-emacs 'y-or-n-p)
3.6.3. Deleting safely
Files deleted with Dired are moved to Trash, rather than obliterated.
(setq delete-by-moving-to-trash t)
3.7. Auto-revert buffers on change
3.7.1. Auto-revert file buffers
I'd like Emacs to watch the files that I'm visiting. When one of them has been changed by another application, Emacs should automatically update the corresponding buffer, so that the file and the buffer remain in sync.
;; Automatically refresh a buffer when the file
;; has been changed on disk.
(global-auto-revert-mode t)
3.7.2. Auto-revert non-file buffers
Also automatically refresh non-file buffers. This is very useful when you're using Dired. Emacs will refresh the Dired buffer, when files get added to or deleted from the directory that you're visiting.
;; Automatically refresh a non-file buffer, when files or folders
;; have been changed externally.
(setq global-auto-revert-non-file-buffers t)
3.8. User prompts
First off, I want Emacs to ask and accept 'y' or 'n' instead of "yes" and "no". Also, I want to be able to use ESC to make prompts go away, like the keybinding C-g does.
Lastly, I'm going to keep Emacs from using dialog boxes to ask questions. Usually it will prompt the user for input or confirmation in the minibuffer. For the confirmation of some actions however, it will prompt using a graphical dialog box. Let's make Emacs always show prompts in the minibuffer, so that I can just type 'y' or 'n' instead of having to reach for the trackpad or my mouse.
;; Accept short answers to prompts.
(defalias 'yes-or-no-p 'y-or-n-p)
;; Make ESC quit out of prompts.
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
;; Don't use dialog boxes to aks questions.
(setq use-dialog-box nil)
3.9. Calendar
To fire up Emacs' built-in calendar, run M-x calendar. By default, it uses Sunday as the first day of the week. Let's change that to Monday.
;; Set Monday as the first day of the week.
(setq calendar-week-start-day 1)
3.10. Setting up Emacs as an edit server
If Emacs is already running, and another application invokes it, don't fire up a new Emacs instance, but use the existing Emacs process as a server. When you're using your file manager or terminal to open a file with Emacs, the file should be opened in the current Emacs instance.
;; Use Emacs as an edit server. Run the server at Emacs start-up,
;; so that all emacsclient calls are routed here.
(use-package server
;; No need to ensure, because it's a built-in package.
;; It's part of Emacs, so we don't want use-package
;; to look for it in the package archives on the web.
:ensure nil
:config
(unless (server-running-p)
(server-start)))
The Emacs manual explains it as follows:
Various programs can invoke your choice of editor to edit a particular piece of text. For instance, version control programs invoke an editor to enter version control logs […]. By convention, your choice of editor is specified by the environment variable EDITOR. If you set EDITOR to "emacs", Emacs would be invoked, but in an inconvenient way — by starting a new Emacs process. This is inconvenient because the new Emacs process doesn't share buffers, a command history, or other kinds of information with any existing Emacs process. You can solve this problem by setting up Emacs as an edit server, so that it "listens" for external edit requests and acts accordingly.
3.11. Composing characters
The latin-9-prefix
input method enables you to compose characters. With this input method set, you can produce characters with accents, and other special characters. Typing "e
, for example, will produce ë
(an e
with an Umlaut), typing ~e
will give you a €
sign, and "s
will get you a ß
.
(set-input-method "latin-9-prefix")
(defun my-activate-default-input-method ()
(interactive)
(activate-input-method default-input-method))
;; Activate default input method for specific modes.
(add-hook 'org-mode-hook 'my-activate-default-input-method)
(add-hook 'text-mode-hook 'my-activate-default-input-method)
(add-hook 'lisp-mode-hook 'my-activate-default-input-method)
;; For writing emails.
(add-hook 'message-mode-hook 'my-activate-default-input-method)
3.12. Searching
Some Isearch (incremental search) tweaks.
;; Show the total number of matches in the minibuffer,
;; along with the current match number.
(setq isearch-lazy-count t)
;; Put this information at the end of the search message,
;; instead of the beginning.
(setq lazy-count-prefix-format nil)
(setq lazy-count-suffix-format " (%s/%s)")
3.13. Custom scratch buffer message
Time to customize the scratch buffer message. Let's throw in some positive affirmation and some exiting instructions (for my significant other).
(setq initial-scratch-message ";; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with C-x C-f and enter text in its buffer.
;; All is well!
;; TO QUIT OUT OF EMACS:
;; 1. Control-x, Control-c, or;
;; 2. Super + Shift + q")
3.14. Tramp
Set the default connection mode to SSH.
(setq tramp-default-method "ssh")
3.15. World time
The M-x world-clock command opens a buffer with the times in the time zones specified in the display-time-world-list
. Very convenient when you're working in a team with remote members.
;; Time zones to display with world-time command.
(setq display-time-world-list
'(("UTC" "UTC")
("Europe/Amsterdam" "Amsterdam")
("Europe/Athens" "Athens")
("Pacific/Auckland" "Auckland")
("Asia/Shanghai" "Bejing")
("Asia/Dubai" "Dubai")
("Europe/Istanbul" "Istanbul")
("Asia/Jakarta" "Jakarta")
("Africa/Johannesburg" "Johannesburg")
("Asia/Kolkata" "Mumbai")
("America/New_York" "New York")
("America/Santiago" "Santiago")
("America/Los_Angeles" "Seattle")
("Australia/Sydney" "Sydney")))
(setq display-time-world-time-format "%a, %d %b %H:%M %p %Z")
(global-set-key (kbd "C-c w") 'world-clock)
3.16. Show start up time and garbage collections
Show the time that Emacs needs to start up in the minibuffer, together with the number of performed garbage collections.
;; Display start up time in minibuffer,
;; together with garbage collections.
(defun my-display-startup-time ()
(message "Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done))
(add-hook 'emacs-startup-hook #'my-display-startup-time)
4. No littering!
I like to keep my init.el and my file system tidy.
4.1. Setting a customization file
The custom-file
variable determines where Emacs will store customization information. Its default value is nil
, which means this data will be saved in your initialization file. I want Emacs to keep it in a seperate file instead of cluttering up my init.el.
;; File to use for storing customization information.
(setq custom-file (concat user-emacs-directory "transient/custom.el"))
;; Load custom-file on start-up.
(load custom-file 'noerror)
4.2. Managing auto-save files
Let's keep Emacs from scattering auto-save files all over the file system. I want it to keep all auto-save files in a single folder. (Make sure that it exists, because Emacs won't ceate it for you if it doesn't).
;; Where to store auto-save files.
(setq auto-save-file-name-transforms '((".*" "~/.config/emacs/transient/autosave-files/" t)))
;; File name in which to write a list of all auto save file names.
;; This variable is initialized automatically from
;; "auto-save-list-file-prefix"shortly after Emacs reads init.el,
;; if you have not yet given it a non-nil value.
(setq auto-save-list-file-name "~/.config/emacs/transient/auto-save-list/my-auto-save-list")
4.3. Managing backup files
Likewise, I want Emacs to keep all backup files in a single directory. (Make sure that it exists: Emacs won't ceate it for you).
(setq backup-directory-alist '((".*" . "~/.config/emacs/transient/auto-backup-files/")))
5. Eye candy
Beauty is in the eye of the beholder, and this beholder is going to spruce up Emacs a bit.
5.1. Various visual tweaks
;; Stop the cursor from blinking.
(blink-cursor-mode 0)
;; Set larger fringes (default is 8px).
(set-fringe-mode 12)
;; Non-nil means a single space does not end a sentence.
;; This is relevant for filling.
(setq sentence-end-double-space nil)
;; Display column numbers in the minibuffer.
(column-number-mode)
;; High-light the current line. You can toggle hl-line-mode:
;; - For the current buffer: M-x hl-line-mode.
;; - Globally:M-x global-hl-line-mode.
;; Let's turn it on globally.
(global-hl-line-mode 1)
;; Display line numbers when in org mode and in programming mode.
(add-hook 'org-mode-hook 'display-line-numbers-mode)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
;; Disable audible bell and enable visible bell
(setq visible-bell t)
;; Visualization of matching parens.
(show-paren-mode)
;; Delay before showing a matching paren.
;; Default value is 0.125 seconds.
(setq show-paren-delay 0.125)
5.2. Hide unneeded GUI elements
I've disabled a couple of GUI elements that I rarely use. If you're new to Emacs, you probably want to comment out the next lines of code.
;; Disable splash screen and startup message.
;; Alternatively, you could use (setq inhibit-startup-message t)
(setq inhibit-splash-screen t)
;; Disable menu-bar-mode.
(menu-bar-mode -1)
;; Toggle menu-bar-mode.
(define-key global-map (kbd "C-c m") #'menu-bar-mode)
;; Disable tool-bar-mode.
(tool-bar-mode -1)
;; No vertical scroll bars.
(scroll-bar-mode -1)
You can also control the menubar, the toolbar and the scrollbar manually, with the following commands:
- M-x menu-bar-mode.
- M-x tool-bar-mode.
- M-x scroll-bar-mode or M-x toggle-scroll-bar.
In addition, you can use F10 to get direct acccess to a floating global menu, or use M-x menu-bar-open.
5.2.1. Hide titlebar when maximized
When Emacs is maximized (to be distinguished from fullscreen), let's hide the title bar to save some screen real estate. This is especially important when I'm using the Gnome desktop.
(add-hook 'window-size-change-functions #'frame-hide-title-bar-when-maximized)
5.3. Mode line
Tip: When you're testing out formatted time strings in the scratch buffer, and you want to immediately see the result after evaluating, just put (display-time-mode 1)
in the scratch buffer and then evaluate the buffer.
;; Don't display the load average.
(setq display-time-default-load-average nil)
;; Show the current time in the mode line.
(display-time-mode 1)
;; Time, day, date, week number.
;; For example: 23:43 thu. 16 jan. wk 02
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Time-Parsing.html
(setq display-time-format "%H:%M %a. %d %b. wk %U")
5.4. Ef themes
The aesthetically pleasing Ef themes have been developed by Protesilaos Stavrou.
(use-package ef-themes
:ensure t
:config
;; Add all your customizations prior to loading the themes.
(setq ef-themes-italic-constructs t
ef-themes-bold-constructs t
ef-themes-variable-pitch-ui nil
ef-themes-mixed-fonts t
ef-themes-to-toggle '(ef-summer ef-night))
;; Load the theme of your choice.
(ef-themes-select 'ef-summer)
;; Switching between two specified EF themes.
;; Use F8 to switch between ef-x and ef-y theme.
;; Toggle between two Ef themes.
(define-key global-map (kbd "<f8>") #'ef-themes-toggle)
;; (global-set-key [f5] 'ef-themes-toggle)
;; Load an Ef theme at random, excluding the current one.
;; With optional VARIANT as a prefix argument, prompt to
;; limit the set of themes to either dark or light variants.
(define-key global-map (kbd "<f9>") #'ef-themes-load-random))
Protesilaos has published an extensive manual for the themes.
5.5. Variable pitch mode
I want Emacs to use a proportional font for my prose, and a fixed font for my code and tables, as well as for text in the mini-buffer.
;; Main typeface.
(set-face-attribute 'default nil :family "Fira Code Retina" :height 110)
;; Monospaced typeface.
;; "Source Code Pro" looks good too.
(set-face-attribute 'fixed-pitch nil :family "Fira Code Retina" :height 0.9)
;; Proportionately spaced typeface.
(set-face-attribute 'variable-pitch nil :family "Open Sans" :height 1.0)
;; Depending on your fonts, you may want to have more or less spacing.
(setq-default line-spacing 0.2)
;; Enable variable-pitch-mode by default in text-mode.
(add-hook 'text-mode-hook 'variable-pitch-mode)
6. Picking up where you've left off
6.1. Save place mode
I want Emacs to remember and restore the last position of the cursor ('point'). Turning on save-place-mode makes Emacs save place in each file: When you visit a file, point goes to the last place where it was when you previously visited it.
;; Remember and restore the last cursor position: The last place
;; where point was when Emacs last visisted the file.
(save-place-mode 1)
6.2. Remember recent files
With recentf-mode enabled, you can use M-x recentf-open-files to create a buffer with recently visited files that you can then easily select and visit again. This command isn't bound to a key by default, so I've created a key-binding. If you want to view recent files in the minibuffer, use M-x recentf.
;; Remember recent files.
(use-package recentf
:ensure nil
:defer 0.1
:bind ("C-c r" . recentf-open-files)
:config
(setq
;; Emacs won't create the "transient" folder for you!
recentf-save-file (concat user-emacs-directory "transient/recentf")
recentf-max-saved-items 1000
;; Default is 10.
recentf-max-menu-items 500
recentf-exclude '("/tmp/" "/ssh:" "*\/.git/COMMIT_EDITMSG"))
(run-with-idle-timer 30 t 'recentf-save-list)
(recentf-mode))
6.3. Remember minibuffer history
I want Emacs to remember what I've entered in the minibuffer, so I can easily retrieve and reuse it. With savehist mode enabled, it will save the minibuffer history to an external file (after exiting, and also periodically). This history will persist over Emacs restarts.
;; Remember minibuffer prompt history.
(use-package savehist
:ensure nil
:init
;; Turn on savehist-mode.
(savehist-mode)
:config
;; Location where Emacs saves the minibuffer history.
(setq savehist-file (concat user-emacs-directory "transient/savehist"))
;; Do save it!
(setq savehist-save-minibuffer-history 1)
;; Periodicity of saving minibuffer histories. Default is 300.
(setq savehist-autosave-interval 50)
;; This variable only affects history lists that don’t specify their own
;; maximum lengths. Setting the "history-length" property of a history
;; variable overrides this default.
;; A number means truncate to that length, and t means no truncation.
;; Default value is 100.
(setq history-length t)
;; Non-nil means to delete duplicates in history. If set to t when adding
;; a new history element, all previous identical elements are deleted from
;; the history list.
(setq history-delete-duplicates t)
;; Save the history of commands invoked via M-x, and more.
(setq savehist-additional-variables
'(command-history
kill-ring
search-ring
regexp-search-ring)))
6.4. Remember and restore buffers from previous session
Let's use the desktop library to make Emacs remember and restore all buffers from the most recent session, so that I can easily continue where I've left off.
To manually save the desktop at any time, use the command M-x desktop-save-in-desktop-dir. If you want to store it in a specified folder, use M-x desktop-save instead. To read it from that folder later on, use M-x desktop-read.
;; Automatically save and restore sessions.
(use-package desktop
;; No need to ensure, because it's a built-in package.
:ensure nil
:config
(setq
;; Location where Emacs saves the desktop file.
desktop-dirname (concat user-emacs-directory "transient")
desktop-base-file-name "emacs.desktop"
desktop-base-lock-name "emacs.desktop.lock"
desktop-path (list desktop-dirname)
desktop-save t
;; Tramp paths
desktop-files-not-to-save "^$"
desktop-load-locked-desktop nil
desktop-auto-save-timeout 10)
:init
;; Turn on desktop-save-mode.
(desktop-save-mode 1))
7. Exploring key bindings
The excellent which-key is a minor mode that displays the key bindings following your currently entered incomplete command (a prefix) in a pop-up. (This package is integrated into the core Emacs distribution as of Emacs 30).
(use-package which-key
:ensure t
:init
(which-key-mode))
8. Expanding abbreviations
In this minor mode, you can type abbreviations that you've defined previously, and then Emacs will automatically expand them to text. You may also want to check out my Yasnippet configuration.
;; Automatic expansion of abbreviations.
;; While the package is called "dabbrev" (short for "dynamic
;; abbreviations"), the mode is called "abbrev-mode".
(use-package dabbrev
:ensure nil
:config
;; Set the file storing the abbreviations / the location of your
;; abbreviation file. You have to create the file manually, if
;; it doesn't exist yet.
(setq abbrev-file-name (concat user-emacs-directory "my-stuff/my-abbreviations-for-abbrev-mode.el"))
;; Abbrev is a minor mode. This is how you turn it on globally.
(setq-default abbrev-mode t)
;; Save abbreviations upon exiting Emacs. By default, Emacs will
;; ask whether you want to save abbreviations when you quit out
;; of Emacs. Let's have Emacs save them silently, without asking.
(setq save-abbrevs t)
;; Read the abbreviation file on startup.
(quietly-read-abbrev-file))
9. Org mode
Org Mode needs some tweaking.
9.1. Basics
Let's improve some basic things first.
(use-package org
:ensure nil
:config
;; Default value is ~/org.
(setq org-directory "~/Documents/")
;; Indent text according to outline structure.
;; May slow Emacs down when opening large files.
;; Then configure on a per-buffer basis, with the
;; "STARTUP" keyword (value "indent" or "noident").
(setq org-startup-indented t)
(setq org-indent-indentation-per-level 2)
;; Keep Org from automatically deciding whether to
;; create new lines around new entries.
;; (customize-set-variable 'org-blank-before-new-entry
;; '((heading . nil)
;; (plain-list-item . nil)))
;; Just don't do it at all.
(setq org-blank-before-new-entry nil)
;; Hide emphasis markers.
;; Display bold, italic, underlined, verbatim text, strike through
;; and code, instead of text between emphasis markers (asterisks,
;; forward slashes, underscores, equal signs, plus signs and tildes).
(setq org-hide-emphasis-markers t)
;; Images.
;; Show images in .org buffers. Display them inline.
;; If Emacs gets slow, try commenting this out and run
;; M-x org-display-inline-images.
(setq org-startup-with-inline-images t)
;; Set the image to a third of the width of the screen.
(setq org-image-actual-width (/ (display-pixel-width) 3))
;; When global-cycling through headers, zero separator-lines
;; between headers will result in a more compact view.
(setq org-cycle-separator-lines 0)
;; Clocking work time.
;; Show 'Total time' exceeding 24 hrs as "26:00",
;; instead of "1d 2"
(setq org-duration-format 'h:mm))
9.2. Global access to important commands
The following Org commands ought to be accessible in any type of Emacs buffer, not just in Org buffers. To achieve this, l've bound them to globally available keys.
(use-package org
:init
;; Org mode - global keybindings.
;; Global access to important Org commands.
(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture))
9.3. Org agenda
Load all .org files in the specified folder to the agenda, so you can generate a global todo list.
(use-package org
:init
;; Initializing "org-agenda-files" variable.
;; I am loading the "org-agenda-files" list from an external file.
(defvar org-agenda-files-file
(thread-last user-emacs-directory (expand-file-name "./private/org-agenda-files.el"))
"Path to file with org-agenda-files list.")
(defun load-my-file (my-file)
"Load specified .el file."
(interactive)
(if (file-exists-p my-file)
(load-file my-file)
(user-error (concat "Missing " my-file " file."))))
(load-my-file org-agenda-files-file))
Alteratively, you could specify a folder (instead of individual files), but this makes Emacs open a buffer for each .org file in the specified folder each time an agenda command is used.
(use-package org
:config
(setq org-agenda-files (list "~/org/" )))
9.4. Workflow states
By default, Org uses only two keywords for todo entries: TODO
and DONE
. I have added WAIT
, SOMEDAY
and CANCELED
" to the list. In many files, I'm using additional keywords. These are listed below under org-todo-keyword-faces
. I've assigned colors to the keywords to make them clearly recognizable. This helps me to quickly get a status overview in a document. Using C-c C-t, or pressing Shift and the left or right arrow, you can conveniently cycle through the various states.
;; Workflow states.
(use-package org
:config
;; Changing state from TODO to DONE (or similar) creates
;; a CLOSED timestamp.
(setq org-log-done 'time)
;; Add some TODO keywords to the default keywords.
(setq org-todo-keywords
'((sequence "TODO" "WAIT" "SOMEDAY" "|" "DONE" "CANCELED")))
;; Set faces (colors) for TODO states.
;; This list includes keywords that I've specified on a per file basis.
;; If you're using Ef themes, get colors by running
;; M-x ef-themes-list-colors-current.
(setq org-todo-keyword-faces
'(
("TODO" . "#e00033")
("WAIT" . "#ffc200")
("DECIDE" . "#a45392")
("SLEEPING" . "#c6bbc6")
("SORT" . "#a6c0ff")
("SOMEDAY" . "#88ccff")
("IDEA" . "#88ccff")
("EDIT" . "#a6c0ff")
("READ". "#a6c0ff")
("CHECK" . "#a6c0ff")
("FIXME" . "#a6c0ff")
("MOVE" . "#a6c0ff")
("REFILE" . "#a6c0ff")
("ARCHIVE". "#61756c")
("FEEDBACK" ."#a6c0ff")
("DONE" . "#007f68")
("DECIDED" . "#007f68")
("OK". "#007f68")
("CANCELED" . "#c6bbc6"))))
9.5. Working with source code
M-x org-babel-demarcate-block (C-c C-v d) is a super convenient command when you're working with src blocks: It wraps or splits the code in the region or on the point.
;; Working with source code - Org babel.
(use-package org
:init
;; You can specify wich programming languages can be evaluated
;; in Org buffers.
;; Allow (t) or disallow (nil) the evaluation or tangling of
;; the following languages.
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(lisp . t)
(scheme . t)
(shell . t)
(java . t)
(js . t)
(python . t)
(css . t)
(sass . t)
(sql . t)
(sqlite . t)
(latex . t)
(haskell . t)
(clojure . t)
(awk . t)
(vala . nil)
(ruby . t)))
:config
;; Working with src blocks.
;; Use this keybinding within a src block: Emacs will open
;; a new buffer for you, where you can edit the code.
(global-set-key (kbd "C-c s") 'org-edit-src-code)
;; Indentation for the content of a source code block.
;; Has no effect if "org-src-preserve-indentation" is non-nil.
(setq org-edit-src-content-indentation 0)
(setq org-src-preserve-indentation t)
;; Don't ask for confirmation to evaluate.
(setq org-confirm-babel-evaluate nil))
9.6. The export dispatcher
Org can export .org files to other formats, such as html, odt, pdf and latex.
;; Export dispatcher.
(use-package org
:config
;; After exporting to "odt", automatically post-process to "pdf".
(setq-default org-odt-preferred-output-format "pdf"))
9.7. Capture templates
Org capture templates allow for quickly capturing information and ideas.
;; Capture templates.
(use-package org
:config
;; Default target for capturing notes: Fall back file
;; for capture templates that don't specify a target file.
(setq org-default-notes-file (concat org-directory "inbox.org"))
(setq org-capture-templates `(("j" "Journal entry")
("jt" "Journal entry - datetree - today" entry
(file+datetree "~/Documents/ADMINISTRATIE/journal-michiel-datetree.org")
"* %^{Enter title}\n:PROPERTIES:\n:CREATED: %U %i\n:END:\n%^{Enter description}%?" :prepend t)
("jc" "Journal entry - datetree - custom date & CREATED date" entry
(file+olp+datetree "~/Documents/ADMINISTRATIE/journal-michiel-datetree.org")
"* %^{Enter title}\n:PROPERTIES:\n:CREATED: %(org-insert-time-stamp (current-time) t t)\n:END:\n %^{Enter description}%?" :time-prompt t :prepend t)
("b" "Bookmark (URL)")
;; Don't delete the underscores, or org will not close off the link
;; and make all tags part of the link too. With prepend we ensure
;; that new entries are added before existing entries.
("bl" "Bookmark to bookmarks list: [[url][description]] information" entry
(file "bookmarks.org")
"* _[[%^{URL}][%^{Description}]]_%^G\n:PROPERTIES:\n: CREATED:%U\n:END:\n\n%?":prepend t :empty-lines 1)
("bc" "Bookmark to current buffer: [[url][description]] information" entry
(file buffer-name)
"* _[[%^{URL}][%^{Description}]]_%^G\n:PROPERTIES:\n: CREATED:%U\n:END:\n\n%?":prepend t :empty-lines 1))))
10. Quick access to frequently used files
I've set up some key bindings for easy access to my Emacs configuration, my init.el, and my time-tracking files. For some of these, I'm loading the keybindings from an external file, because I want to keep the location of the files private. It might not be the most elegant solution, but it does the job. However, I can disclose what the code in these external files looks like (see the snippet after the following block).
;; Keybindings for quick access to frequently used files.
;; Keybinding for opening Emacs config file.
(defvar file-with-keybinding-to-my-emacs-config-file
(thread-last user-emacs-directory (expand-file-name "./private/keybinding-to-my-emacs-config.el"))
"Path to file with org-agenda-files list.")
(load-my-file file-with-keybinding-to-my-emacs-config-file)
;; Keybinding for opening init.el (useful for debugging).
(global-set-key (kbd "<f12>") (lambda () (interactive) (find-file-other-window user-init-file)))
;; Keybinding for opening my time tracking file.
(defvar file-with-keybinding-to-access-time-tracking-file
(thread-last user-emacs-directory (expand-file-name "./private/keybinding-to-time-tracking-file.el"))
"Path to file with org-agenda-files list.")
(load-my-file file-with-keybinding-to-access-time-tracking-file)
This snippet shows how you can create a keybinding for quick access to a file, your literate Emacs configuration for example.
;; Open Emacs config.
(global-set-key (kbd "C-c i") (lambda () (interactive) (find-file "~/emacs-config.org")))
11. My functions
The following functions make my life a bit easier. They're (interactive)
, so you can invoke them with M-x.
11.1. Reload my Emacs config
When I've changed and tangled my Emacs configuration, I want to be able to reload init.el without having to exit and restart Emacs.
;; Reload init.el file.
(defun my-reload-emacs-configuration ()
"Reload init.el file."
(interactive)
(load-file user-init-file))
11.2. Show current date and time in minibuffer
This function displays the current date and time in the minibuffer, with some extra information.
;; Show current date and time in minibuffer.
(defun my-display-date-time ()
"Show current date, time & more in minibuffer."
(interactive)
(message (format-time-string "%Y-%m-%d - %H:%M:%S UTC%:z - %A - day %j week %U quarter %q")))
(global-set-key (kbd "C-c d") 'my-display-date-time)
;; I haven't decided yet which name I'm going to keep.
(defun my-display-now ()
"Show current date, time & more in minibuffer."
(interactive)
(my-display-date-time))
(global-set-key (kbd "C-c n") 'my-display-now)
The output looks like this:
2025-02-16 - 23:12:47 UTC+0100 - sunday - day 047 week 07 quarter 1
11.3. Clear the kill ring
Useful for getting rid of private information on the kill-ring.
;; Clear the kill ring.
(defun my-clear-kill-ring ()
"Clear the kill ring."
(interactive)
(setq kill-ring nil))
11.4. Get ready for work
Pull up my inbox file and my task management file, side by side, so I can hit the ground running.
(defun my-get-ready-for-work ()
"Open important files side by side, in fullscreen."
(interactive)
;; I want to end up with two windows, even if
;; multiple windows are already open.
(when (> (length (window-list)) 1)
(delete-other-windows))
;; This file is for starting new notes, and for
;; quickly capturing information and ideas.
(find-file (concat org-directory "1.org"))
;; Alternatively, use (split-window-horizontally).
(split-window-right)
;; Visit the first file in the list "org-agenda-files".
;; This file contains my administration and TODO tasks.
(find-file (car org-agenda-files)))
(global-set-key (kbd "C-c g") 'my-get-ready-for-work)
11.5. Transparent background
This is a slightly modified version of a function published on Kristoffer Balintona's blog. The frame parameter alpha-background
controls the transparency of the text background. It does not affect the opacity of the text itself.
;; Toggle background opacity (transparency) of frame.
(defun my-toggle-window-transparency ()
"Toggle frame's background transparency."
(interactive)
(let ((desired-value 85))
(set-frame-parameter nil 'alpha-background
(if (not (frame-parameter nil 'alpha-background)) desired-value))))
(define-key global-map (kbd "C-c o") #'my-toggle-window-transparency)
If you're using Sway, you may want to control opacity from your Sway config instead of your Emacs config.
12. External packages
12.1. Olivetti mode for writers
Olivetti is a simple Emacs minor mode for a nice writing environment.
(use-package olivetti
:ensure
:init
;; Width of text body: Use an integer (columns) if you want
;; it to remain constant. Use a floating point value if you
;; want it to change with window width.
(setq olivetti-body-width 86)
(setq olivetti-style 'fancy)
:hook
(org-mode . olivetti-mode)
;; View elfeed articles in Olivetti mode.
(elfeed-show-mode . olivetti-mode))
12.2. In buffer completion with Company mode
Company mode is a modular in-buffer text completion framework. Its name is short for "complete anyhing". You can manually toggle this mode in the current buffer with M-x company-mode. More information is available on the project's website.
(use-package company
:ensure t
:init
;; Enter company-mode at start-up.
(add-hook 'after-init-hook 'global-company-mode)
:config
;; Enable company-mode everywhere for everything, except
;; for modes in which auto-completion might cause problems.
(setq company-global-modes
'(not magit-status-mode
help-mode))
;; When should company show completion options?
;; Immediately after two characters have been typed.
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 2)
;; When you reach the end of the list of completion
;; options, wrap around to the top of the list.
(setq company-selection-wrap-around t)
;; I like using Tab to cycle through the completion list.
;; "tng" means "tab and go".
(company-tng-configure-default))
12.3. Minibuffer completion with Vertico
Vertico is a minibuffer completion framework. Its name stands for "vertical interactive completion". It sorts by history position (see my minibuffer history configuration).
(use-package vertico
:ensure t
:init
(add-hook 'after-init-hook 'vertico-mode)
:config
;; When you reach the end of the list of completion
;; options, wrap around to the top of the list.
(setq vertico-cycle t))
12.3.1. Marginalia in the minibuffer
The Marginalia package provides marginalia-mode which adds annotations (marginalia) to the minibuffer completions.
;; Annotations for minibuffer completions.
(use-package marginalia
:ensure t
:init
(marginalia-mode))
12.4. Orderless
Orderless enables you to quickly sort and filter lists of completion candidates in the minibuffer. It provides various "completion styles", which are back-ends for completion that you can use from a completion UI. For example, from the minibuffer tab completion UI (the default Emacs completion UI), from the built-in Icomplete package, or from a third party minibuffer completion framework like Vertico.
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
12.5. Yasnippet - text and code expansion
Yasnippet is a template system for Emacs: You can type an abbreviation, and then Yasnippet will automatically expand it to a snippet of text or code. From its extensive documentation, you can learn how to create templates with placeholder fields, or templates that work with Elisp.
(use-package yasnippet
:ensure t
:config
;; Initialize "yas-snippet-dirs" variable.
;; I am loading my feeds list from an external file.
(defvar yas-snippet-dirs-file
(thread-last user-emacs-directory (expand-file-name "./private/yas-snippet-dirs.el"))
"Path to file with yas-snippet-dirs list.")
(load-my-file yas-snippet-dirs-file)
;; This has to come after setting up yas-snippet-dirs!
(yas-global-mode 1)
;; Activate the (appropriate) snippets.
(add-hook 'yas-minor-mode-hook (lambda () (yas-activate-extra-mode 'fundamental-mode))))
You may also want to check out my Dabbrev configuration.
12.6. Org superstar
Org superstar prettifies headings and plain lists in Org mode. It gives us good looking bullets instead of plain asterisks.
(use-package org-superstar
:ensure t
:config
;; Set space character as a leading bullet(s),
;; and get rid of the leading dots. Only used for
;; graphical displays.
(setq org-superstar-leading-bullet ?\s)
;; For terminal displays.
(setq org-superstar-leading-fallback ?\s)
;; The following expression lists the default
;; org-superstar symbols for headline bullets.
;; Change it if you want to set custom symbols
;; for headline bullets.
;; (setq org-superstar-headline-bullets-list '("◉" "○" "✸" "✿"))
;; If you want to get rid of headline indentation:
;; (setq org-superstar-remove-leading-stars t)
;; Hook org-superstar-mode to org-mode.
:hook (org-mode . org-superstar-mode))
Before I switched to org-superstar, I used org-bullets.
12.7. Org appear
The org-appear package makes invisible parts of Org elements appear, when your cursor enters the element. Hidden emphasis markers, for example: Emacs will hide these markers from view, since I've set org-hide-emphasis-markers
to t
. Or think of the hidden square brackets of Org hyperlinks. With org-appear, you can toggle their visibility by entering and leaving the enclosed text.
(use-package org-appear
:ensure t
:init
;; Toggle links.
(setq org-appear-autolinks t)
;; Toggle subscripts and superscripts.
(setq org-appear-autosubmarkers t)
;; Toggle Org entitites.
(setq org-appear-autoentities t)
;; Toggle keywords as defined in org-hidden-keywords.
(setq org-appear-autokeywords t)
;; When to toggle elements.
(setq org-appear-trigger 'always)
;; Seconds of delay before toggling.
(setq org-appear-delay 0.135)
:hook
;; Run org-appear automatically on org-mode start-up.
(org-mode . org-appear-mode))
12.8. RSS feeds with Elfeed
Elfeed is an extensible web feed reader for Emacs, supporting both Atom and RSS.
(use-package elfeed
:ensure t
:init
;; Initialize "elfeed-feeds" variable.
;; I am loading my elfeed-feeds list from an external file.
(defvar elfeed-feeds-file
(thread-last user-emacs-directory (expand-file-name "./private/elfeed-feeds.el"))
"Path to file with elfeed-feeds list.")
(load-my-file elfeed-feeds-file)
:config
;; By default, Elfeed maintains a database in ~/.elfeed.
;; This location is configurable.
(setq elfeed-db-directory (thread-last user-emacs-directory (expand-file-name "./private/elfeed-database"))))
;; Keybinding for easy access to my feeds.
(global-set-key (kbd "C-c e") 'elfeed)
12.9. Webserver
Simple-httpd is an Emacs webserver for local files, so you can pull up your freshly baked website on http://localhost:8080. Key commands to control it are:
- m-x httpd-start.
- m-x httpd-serve-directory.
- m-x httpd-stop.
Files are served from httpd-root
on httpd-port
. You can change the httpd-root
directory at any time, using M-x httpd-serve-directory.
(use-package simple-httpd
:ensure t
:init
(defvar httpd-root-variable-file
(thread-last user-emacs-directory
(expand-file-name "./private/httpd-root-variable.el"))
"Path to file initializing 'httpd-root' variable")
(load-my-file httpd-root-variable-file)
:config
;; Local host port.
(setq httpd-port 8080)
;; Enable directory listings.
(setq httpd-listings t))
12.10. Avy - Jumping to visible text in tree-style
With Emacs' built-in iSearch (incremental search), searching for a word, and jumping to it once you've found it, is really easy. Just type C-s followed by the character sequence that you're looking for, repeat this keybinding until you've found the desired instance, and then hit Enter to jump to it. Want to search and jump in reverse direction? Just use C-r.
With Avy you can try a different approach. Avy enables you to search for text and jump to it via a character based decision tree. Try the following commands to see how it works.
- M-x avy-go-to-char.
- M-x avy-go-to-char-2.
- M-x avy-go-to-char-below.
- M-x avy-go-to-char-2-above.
(use-package avy
:ensure t
:bind (("C-;" . avy-goto-word-1)))