Minimal Emacs Configuration in Thirty Minutes

Published October 7, 2023 Modified June 12, 2024 emacs screenshot

If you are having trouble, write the files in another text editor, then open Emacs when you are finished. Remember that you can move your cursor to the closing parenthesis of an expression and press C-x C-e to have it evaluated. If you wish to read the documentation for a function or variable, hit C-h f or C-h v and type its name.

Your Emacs configuration will live within ~/.emacs.d by default. Emacs will automatically load two files named early-init.el and init.el. The early-init.el file will contain settings related to GUI and font. Putting these here will improve startup speed since Emacs won’t load unneeded data into memory.

;; Turn off unwanted GUI elements.
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)
(tooltip-mode -1)

;; Set the default font.
;; Append a size -NN to the font name.
(add-to-list 'default-frame-alist
             '(font . "Iosevka Nerd Font-15"))

If you want even faster startup, you can increase the garbage collection threshold. This setting will be amended later.

(setq gc-cons-threshold 134217728)

Now onto init.el. You can place all of your configurations here, but it would be wise to split them up into multiple files. To this end, add a function that will load elisp files. It is used immediately to load settings.el. You can give each module whatever name you want.

(defun my/load-config-file (file)
  "Load elisp FILE."
  (load (expand-file-name file "~/.emacs.d/")))

(my/load-config-file "settings")

Settings

In settings.el, here are some things you might like to add.

As you use Emacs, you will notice it adds a large block of code at the end of your init.el. This is part of the graphical customization interface. Since you are configuring Emacs with elisp files, you won’t need it. Set the custom-file variable to have this code sent elsewhere. If you still want its contents loaded, use the function you created earlier.

(setq custom-file "~/.emacs.d/custom-file.el")

Have Emacs do garbage collection when it is out of focus. This should prevent freezing, but if you still experience lag, set the threshold back to its default value.

(if (boundp 'after-focus-change-function)
    (add-function :after after-focus-change-function
                  (lambda () (unless (frame-focus-state)
                          (garbage-collect))))
  (add-hook 'after-focus-change-function
            'garbage-collect))

;; If you still experience freezing.
(setq gc-cons-threshold 800000)

Set your username and email. This will facilitate sending mail to others.

(setq user-full-name "Your Name")
(setq user-mail-address "yourname@mail.com")

Set an internet browser for opening links.

(setq browse-url-generic-program (executable-find "/usr/bin/firefox"))
(setq browse-url-browser-function 'browse-url-generic)

Set fixed and variable pitch fonts. Ensure Emacs always uses UTF-8.

(set-face-attribute 'fixed-pitch nil :font "Iosevka Nerd Font-15")
(set-face-attribute 'variable-pitch nil :font "Nimbus Sans-15")
(set-language-environment "UTF-8")

Display the current column number in the mode line, and display line numbers on all buffers.

(column-number-mode 1)
(global-display-line-numbers-mode 1)

Automatically add the closing pair when you type a parenthesis or bracket. Disable strange auto-indentation behavior. Insert spaces instead of tabs. Set tab width to two spaces.

(electric-pair-mode 1)
(electric-indent-mode -1)
(setq-default tab-width 2)
(setq-default indent-tabs-mode nil)
(setq-default indent-line-function 'insert-tab)

Have Emacs maintain a history of mini buffer commands and opened files. This will make it easier to get back to things you were doing.

(savehist-mode 1)
(recentf-mode 1)

Disable lock file creation, and send backups to a designated directory. This will prevent Emacs from cluttering your file system.

(setq backup-directory-alist '(("." . "~/.saves")))
(setq backup-by-copying t)
(setq version-control t)
(setq delete-old-versions t)
(setq create-lockfiles nil)

Mouse wheel scroll can be unwieldy. Emacs also loves to make large and jarring jumps as you scroll. Set these to make it more natural.

(setq mouse-wheel-progressive-speed nil)
(setq scroll-conservatively 101)

Taking certain actions in Emacs will prompt for a yes or no answer. The first variable will permit answers with a simple y or n. The second will disable a dialog box which would appear if you took the action using the mouse (such as closing an unsaved buffer with the mouse). The keyboard prompt is given instead.

(setq use-short-answers t)
(setq use-dialog-box nil)

When Emacs starts, a screen is displayed that directs you to documentation. You can disable it, along with the messages buffer to keep the initial workspace minimal.

(setq inhibit-startup-message t)
(setq message-log-max nil)
(kill-buffer "*Messages*")

You will still be left with a scratch buffer which cannot be disabled. You can set its initial content to a string, or nil if you want it to be empty. Also set it to fundemental-mode to disable elisp syntax highlighting.

(setq initial-scratch-message nil)
(setq initial-major-mode 'fundamental-mode)

You can have Emacs automatically enable spell checking and set a variable pitch font in text-mode buffers. These are buffers where you edit things meant to be read such as Markdown and Org files. Make sure you install hunspell for spell checking to work.

(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'text-mode-hook 'variable-pitch-mode)

As for prog-mode buffers, which are used for source code files, you might want to enable line truncation, rather than have lines wrap. You can also enable a highlight on the line your cursor is currently on.

(add-hook 'prog-mode-hook
          (lambda () (toggle-truncate-lines 1)))
(add-hook 'prog-mode-hook 'hl-line-mode)

All of these hooks can be run on any mode you want. You can use a variable pitch font in prog-mode if you want.

Packages

Back inside init.el, add a command to load packages.el.

(my/load-config-file "packages")

Now in packages.el, start by adding Melpa to the archives list. It has many packages not available on GNU Elpa.

(require 'package)
(add-to-list 'package-archives
  '("melpa" . "https://melpa.org/packages/") t)

Now make a function that will check if a package is installed, and if it isn’t, install it.

(defun my/install-package (package)
  "Install PACKAGE."
  (unless (package-installed-p package)
    (package-install package)))

If you like the Vim editing style, install evil and evil-collection to enable Vim features across Emacs. If you use SPC as your leader key, it is critical that you blacklist the key from being bound by evil-collection. Otherwise, SPC will not work as a leader key in many buffers.

(my/install-package 'evil)
(setq evil-want-keybinding nil
  evil-auto-indent nil
  evil-want-C-u-scroll t
  evil-shift-width 2
  evil-undo-system 'undo-redo
  evil-vsplit-window-right t)
(evil-mode t)

(my/install-package 'evil-collection)
(setq evil-collection-key-blacklist '("SPC"))
(with-eval-after-load 'evil
  (evil-collection-init))

Add some packages to improve the look of Emacs. The Modus Themes are built in. You can install the package version if you need options optimized for color blindness.

;; (my/install-package 'modus-themes)
(setq modus-themes-mixed-fonts t
      modus-themes-italic-constructs t
      modus-themes-bold-constructs t
      modus-themes-variable-pitch-ui t
      modus-themes-headings '((1 1.728) (2 1.44) (3 1.2)))
(load-theme 'modus-vivendi)

;; Run this command to get the required icons.
;; M-x nerd-icons-install-fonts
(my/install-package 'doom-modeline)
(doom-modeline-mode t)

(my/install-package 'dashboard)
(setq dashboard-center-content t
;;  Set this to the image you want displayed.
;;  dashboard-startup-banner "~/Images/.emacs.jpg"
    dashboard-display-icons-p nil)
(dashboard-setup-startup-hook)

Packages to improve the usability of the mini buffer, including orderless fuzzy search.

(my/install-package 'vertico)
(setq vertico-count 12)
(vertico-mode t)

(my/install-package 'marginalia)
(marginalia-mode t)

(my/install-package 'orderless)
(setq completion-styles '(orderless basic)
  completion-category-defaults nil
  completion-category-overrides
  '((file (styles partial-completion))))

(my/install-package 'consult)
(setq consult-preview-key nil)

Corfu for code completions. Hit M-SPC while the completion window is up to fuzzy search for what you want.

(my/install-package 'corfu)
(setq corfu-auto t)
(global-corfu-mode t)

Keymaps

This is the last file for the guide.

(my/load-config-file "keymaps")

If you are using Evil, begin by setting a leader key. Then make some keymaps. These are just a few to give you an idea.

(evil-set-leader '(normal visual) (kbd "SPC"))
(evil-define-key 'normal 'global
  (kbd "<leader>x") 'execute-extended-command
  (kbd "<leader>ff") 'project-find-file
  (kbd "<leader>fs") 'consult-buffer
  (kbd "<leader>fl") 'consult-ripgrep
  (kbd "<leader>fo") 'consult-recent-file
  (kbd "<leader>fj") 'consult-outline)

Conclusion

That’s all there is to it. Emacs often looks intimidating to new people. The countless fancy, complex configurations on the internet definitely aren’t helping. If you start with an empty canvas, and take things slow, I believe you will come to love this program.

You can view my personal configuration on SourceHut.