Welcome! This Emacs “distro” is based on my personal Emacs configuration (on GNU Emacs 26.3). It’s unopinionated and was created for general use in mind. The package settings are grouped in a logical manner, and I’ve documented as detailed as possible what each code snippet does in this file.
Clean up the UI and enhance some basic defaults defined in “C Source
Code”. The variable ian/indent-width
controls the default
indentation across various programming modes. The default is 4, you
can change this variable to 2 or any other indentation width you
prefer, and the change will be made across all programming language
modes including C, C++, Java, Python etc. (Exception: JavaScript
defaults to 2-space indent, you can still set it to any other
indentation width you prefer in the web-mode
section.)
(use-package emacs
:preface
(defvar ian/indent-width 4) ; change this value to your preferred width
:config
(setq frame-title-format '("Yay-Evil") ; Yayyyyy Evil!
ring-bell-function 'ignore ; minimize distraction
frame-resize-pixelwise t
default-directory "~/")
(tool-bar-mode -1)
(menu-bar-mode -1)
;; better scrolling experience
(setq scroll-margin 0
scroll-conservatively 101 ; > 100
scroll-preserve-screen-position t
auto-window-vscroll nil)
;; Always use spaces for indentation
(setq-default indent-tabs-mode nil
tab-width ian/indent-width)
;; Omit default startup screen
(setq inhibit-startup-screen t))
;; The Emacs default split doesn't seem too intuitive for most users.
(use-package emacs
:ensure nil
:preface
(defun ian/split-and-follow-horizontally ()
"Split window below."
(interactive)
(split-window-below)
(other-window 1))
(defun ian/split-and-follow-vertically ()
"Split window right."
(interactive)
(split-window-right)
(other-window 1))
:config
(global-set-key (kbd "C-x 2") #'ian/split-and-follow-horizontally)
(global-set-key (kbd "C-x 3") #'ian/split-and-follow-vertically))
Since we’re using use-package as our package management system, we
might as well try to organize under the same syntax as much as
possible to keep the configuration consistent. The option
use-package-always-ensure
is turned on in init.el
, so we’ll add
:ensure nil
when configuring the built-in packages.
Replace the active region just by typing text, just like modern editors.
(use-package delsel
:ensure nil
:config (delete-selection-mode +1))
(use-package scroll-bar
:ensure nil
:config (scroll-bar-mode -1))
(use-package simple
:ensure nil
:config (column-number-mode +1))
Don’t bother confirming killing processes and don’t let backup~ files scatter around.
(use-package files
:ensure nil
:config
(setq confirm-kill-processes nil
create-lockfiles nil ; don't create .# files (crashes 'npm start')
make-backup-files nil))
Auto refreshes every 2 seconds. Don’t forget to refresh the version control status as well.
(use-package autorevert
:ensure nil
:config
(global-auto-revert-mode +1)
(setq auto-revert-interval 2
auto-revert-check-vc-info t
global-auto-revert-non-file-buffers t
auto-revert-verbose nil))
Slightly shorten eldoc display delay.
(use-package eldoc
:ensure nil
:diminish eldoc-mode
:config
(setq eldoc-idle-delay 0.4))
For Java and C/C++, change the formatting style from GNU (the default)
to the more standard K&R. Here we also set the indentation width of C,
C++, Java, and Python to the preferred value defined in
ian/indent-width
(all languages default to 4, except JavaScript,
which is 2, as controlled in web-mode
). Of course, you can change
the value depending on the language as well.
;; C, C++, and Java
(use-package cc-vars
:ensure nil
:config
(setq-default c-basic-offset ian/indent-width)
(setq c-default-style '((java-mode . "java")
(awk-mode . "awk")
(other . "k&r"))))
;; Python (both v2 and v3)
(use-package python
:ensure nil
:config (setq python-indent-offset ian/indent-width))
By default, the scrolling is way too fast to be precise and helpful, let’s tune it down a little bit.
(use-package mwheel
:ensure nil
:config (setq mouse-wheel-scroll-amount '(2 ((shift) . 1))
mouse-wheel-progressive-speed nil))
Reduce the highlight delay to instantly.
(use-package paren
:ensure nil
:init (setq show-paren-delay 0)
:config (show-paren-mode +1))
Maximize the frame by default on start-up. Set the font to size 12.
(use-package frame
:preface
(defun ian/set-default-font ()
(interactive)
(when (member "Consolas" (font-family-list))
(set-face-attribute 'default nil :family "Consolas"))
(set-face-attribute 'default nil
:height 120
:weight 'normal))
:ensure nil
:config
(setq initial-frame-alist '((fullscreen . maximized)))
(ian/set-default-font))
Enter ediff with side-by-side buffers to better compare the differences.
(use-package ediff
:ensure nil
:config
(setq ediff-window-setup-function #'ediff-setup-windows-plain)
(setq ediff-split-window-function #'split-window-horizontally))
Electric-pair-mode has improved quite a bit in recent Emacs versions. No longer need an extra package for this. It also takes care of the new-line-and-push-brace feature.
(use-package elec-pair
:ensure nil
:hook (prog-mode . electric-pair-mode))
(use-package whitespace
:ensure nil
:hook (before-save . whitespace-cleanup))
Delete intermediate buffers when navigating through dired.
(use-package dired
:ensure nil
:config
(setq delete-by-moving-to-trash t)
(eval-after-load "dired"
#'(lambda ()
(put 'dired-find-alternate-file 'disabled nil)
(define-key dired-mode-map (kbd "RET") #'dired-find-alternate-file))))
(use-package cus-edit
:ensure nil
:config
(setq custom-file (concat user-emacs-directory "to-be-dumped.el")))
Many Emacsers love having tons of packages – and that’s absolutely fine! However, one of the goals of the Yay-Evil distro is to provide an essential-only foundation for users to build upon. Therefore, only the most important packages and/or lightweight improvements will be included here. For example, completion frameworks like Ivy or Helm are considered heavy by many, yet the built-in Ido serves almost the same purpose. The only arguably opinionated package is probably Evil, but you probably saw that coming from the distro name, didn’t you ;) ? If you prefer the default keybindings, simply disable the section that controls the Evil behaviors.
Normally, we need to add :ensure t
to tell use-package
to download packages when it’s not available. But since we’ve added use-package-always-ensure
in init.el
, we can omit it.
(add-to-list 'custom-theme-load-path (concat user-emacs-directory "themes/"))
(load-theme 'wilmersdorf t) ; an orginal theme created by me.
(use-package dashboard
:config
(dashboard-setup-startup-hook)
(setq dashboard-startup-banner 'logo
dashboard-banner-logo-title "Yay Evil!"
dashboard-items nil
dashboard-set-footer nil))
Lightweight syntax highlighting improvement for numbers and escape
sequences (e.g. \n, \t
).
(use-package highlight-numbers
:hook (prog-mode . highlight-numbers-mode))
(use-package highlight-escape-sequences
:hook (prog-mode . hes-mode))
I personally find Vi(m) bindings to be the most efficient way of
editing text (especially code). I also changed the default :q
and
:wq
to be killing current buffer, instead of killing the frame or
subsequently killing Emacs.
(use-package evil
:diminish undo-tree-mode
:init
(setq evil-want-C-u-scroll t
evil-want-keybinding nil
evil-shift-width ian/indent-width)
:hook (after-init . evil-mode)
:preface
(defun ian/save-and-kill-this-buffer ()
(interactive)
(save-buffer)
(kill-this-buffer))
:config
(with-eval-after-load 'evil-maps ; avoid conflict with company tooltip selection
(define-key evil-insert-state-map (kbd "C-n") nil)
(define-key evil-insert-state-map (kbd "C-p") nil))
(evil-ex-define-cmd "q" #'kill-this-buffer)
(evil-ex-define-cmd "wq" #'ian/save-and-kill-this-buffer))
Evil-collection covers more parts of Emacs that the original Evil doesn’t support (e.g. Packages buffer, eshell, calendar etc.)
(use-package evil-collection
:after evil
:config
(setq evil-collection-company-use-tng nil)
(evil-collection-init))
Emulates tpope’s vim commentary package (Use gcc
to comment out a line,
gc
to comment out the target of a motion (for example, gcap
to
comment out a paragraph), gc
in visual mode to comment out the
selection etc.)
(use-package evil-commentary
:after evil
:diminish
:config (evil-commentary-mode +1))
Tell magit to automatically put us in vi-insert-mode when committing a change.
(use-package magit
:bind ("C-x g" . magit-status)
:config (add-hook 'with-editor-mode-hook #'evil-insert-state))
Selecting buffers/files with great efficiency. In my opinion, Ido is
enough to replace Ivy/Counsel and Helm. We install ido-vertical to get
a better view of the available options (use C-n
, C-p
or arrow keys
to navigate). Ido-ubiquitous (from the ido-completing-read+
package)
provides us ido-like completions in describing functions and variables
etc. Fuzzy matching is a nice feature and we have flx-ido for that
purpose.
(use-package ido
:config
(ido-mode +1)
(setq ido-everywhere t
ido-enable-flex-matching t))
(use-package ido-vertical-mode
:config
(ido-vertical-mode +1)
(setq ido-vertical-define-keys 'C-n-C-p-up-and-down))
(use-package ido-completing-read+ :config (ido-ubiquitous-mode +1))
(use-package flx-ido :config (flx-ido-mode +1))
Use C-n
and C-p
to navigate the tooltip.
(use-package company
:diminish company-mode
:hook (prog-mode . company-mode)
:config
(setq company-minimum-prefix-length 1
company-idle-delay 0.1
company-selection-wrap-around t
company-tooltip-align-annotations t
company-frontends '(company-pseudo-tooltip-frontend ; show tooltip even for single candidate
company-echo-metadata-frontend))
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous))
A modern on-the-fly syntax checking extension – absolute essential
(use-package flycheck :config (global-flycheck-mode +1))
Some minimal org mode tweaks: org-bullets gives our headings (h1, h2, h3…) a more visually pleasing look.
(use-package org
:hook ((org-mode . visual-line-mode)
(org-mode . org-indent-mode)))
(use-package org-bullets :hook (org-mode . org-bullets-mode))
Markdown mode and Web mode, the latter covers our usages of HTML/CSS/JS/JSX/TS/TSX/JSON.
(use-package markdown-mode
:hook (markdown-mode . visual-line-mode))
(use-package web-mode
:mode (("\\.html?\\'" . web-mode)
("\\.css\\'" . web-mode)
("\\.jsx?\\'" . web-mode)
("\\.tsx?\\'" . web-mode)
("\\.json\\'" . web-mode))
:config
(setq web-mode-markup-indent-offset 2) ; HTML
(setq web-mode-css-indent-offset 2) ; CSS
(setq web-mode-code-indent-offset 2) ; JS/JSX/TS/TSX
(setq web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'"))))
The diminish package is used to hide unimportant minor modes in the
modeline. It provides the :diminish
keyword we’ve been using in
other use-package declarations.
(use-package diminish
:demand t)
Provides us with hints on available keystroke combinations.
(use-package which-key
:diminish which-key-mode
:config
(which-key-mode +1)
(setq which-key-idle-delay 0.4
which-key-idle-secondary-delay 0.4))
(use-package exec-path-from-shell
:config (when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))