Yay-Evil distro by Ian Y.E. Pan
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.
Settings without corresponding packages
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 :ensure nil :preface (defvar ian/indent-width 4) ; change this value to your preferred width (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 (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) ;; The Emacs default split doesn't seem too intuitive for most users. (global-set-key (kbd "C-x 2") #'ian/split-and-follow-horizontally) (global-set-key (kbd "C-x 3") #'ian/split-and-follow-vertically) ;; Omit default startup screen (setq inhibit-startup-screen t))
Configuration for built-in packages
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.
Modernize selection behavior
Replace the active region just by typing text, just like modern editors.
(use-package delsel :ensure nil :config (delete-selection-mode +1))
Disable scroll-bar
(use-package scroll-bar :ensure nil :config (scroll-bar-mode -1))
Enable column numbers
(use-package simple :ensure nil :config (column-number-mode +1))
File-related tweaks
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))
Automatically refreshes the buffer for changes outside of Emacs
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))
Eldoc: documentation in the mini-buffer
Slightly shorten eldoc display delay.
(use-package eldoc :ensure nil :diminish eldoc-mode :config (setq eldoc-idle-delay 0.4))
Indentation improvement
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))
Mouse wheel (track-pad) scroll speed
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))
Show matching parentheses
Reduce the highlight delay to instantly.
(use-package paren :ensure nil :init (setq show-paren-delay 0) :config (show-paren-mode +1))
Setting up some frame defaults
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))
Ediff tweaks
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))
Auto-pairing quotes and parentheses etc.
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))
Clean up whitespace on save
(use-package whitespace :ensure nil :hook (before-save . whitespace-cleanup))
Remember the last place you visited in a file
(use-package saveplace :ensure nil :config (save-place-mode +1))
Display line numbers in programming buffers
(use-package display-line-numbers :ensure nil :hook (prog-mode . display-line-numbers-mode) :config (setq-default display-line-numbers-width 3))
Dired tweaks
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))))
Dump custom-set-variables to a garbage file and don’t load it
(use-package cus-edit :ensure nil :config (setq custom-file (concat user-emacs-directory "to-be-dumped.el")))
Third-party packages
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.
GUI enhancements
Load custom theme
(add-to-list 'custom-theme-load-path (concat user-emacs-directory "themes/")) (load-theme 'wilmersdorf t) ; an orginal theme created by me.
Dashboard welcome page
(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))
Syntax highlighting
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))
Vi keybindings
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))
Git Integration
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))
Searching/sorting enhancements & project management
Ido, ido-vertical, ido-ubiquitous and fuzzy matching
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))
Programming language support and utilities
Company for auto-completion
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))
Flycheck
A modern on-the-fly syntax checking extension – absolute essential
(use-package flycheck :config (global-flycheck-mode +1))
Org Mode
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))
Useful major modes
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]?\\'"))))
Miscellaneous
Diminish minor modes
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)
Which-key
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))
Configure PATH on macOS
(use-package exec-path-from-shell :config (when (memq window-system '(mac ns x)) (exec-path-from-shell-initialize)))