Emacs Config Redo - Evil & Use-Package
Roger Williams Park, Providence RI
After switching to Spacemacs for the last year
or two, it’s about time to back and pull together my own emacs
configuration again. However, spacemacs has shown me several packages
that I want to incorporate into my new emacs setup. Rather than
resurrect and Frankenstein the changes into my old .emacs
file… I’m starting from scratch.
Evil Mode
History
The one emacs package that spacemacs really got me addicted to was Evil, which emulates the main features of the vim text editor. I started with emacs in college, but eventually switched to Vim which, became the first power editor that I really got into (I even bought a book to learn it better). I stuck with Vim until I became a professional LISP developer, and the switch back to Emacs was impossible to ignore, and obvious.
Even after switching to back Emacs, I have still enjoyed using command
line applications like cmus,
ranger, and
w3m, many of which are influenced by Vim
and often incorporate similar keyboard commands (at least the j
,
k
, l
, ;
navigation). While it isn’t ideal for everything (I
prefer to write, but not necessarily edit code with emacs-syle
navigation), I never lost my love for the homerow-centric, and
efficient vim-style movement commands.
Best of Both Worlds
For the last two years, Spacemacs’s default
Vim configuration has provided the best of both worlds. It had all of
the Evil packages pre-configured and optimized, but I could simply hit
Ctrl-z
, and jump back to Emacs-mode.
Spacemacs was easy to use and I enjoyed it, but it really started to
have stability issues on my Windows 10 work computer. I thought that
going back to a stock emacs configuration may tone down the
complexity, and increase stability. I started to build a new
configuration based around Evil
. During setup, I was happily
surprised to learn that the Ctrl-z
option to switch back to
Emacs-mode was a default Evil
behavior… so I still have the best of
both worlds!
Starting Config
Here is my starting Evil
setup. I’ve nested other use-packages
inside of it, so that if evil
is configured, the packages that
depend on it go ahead and configure themselves too. I’m sure this will
grow over time as I add missing packages, but so far, it seems to
provide all the core functionality I need.
;; Evil Mode
(use-package evil
:ensure t
:config
(evil-mode 1)
(use-package evil-leader
:ensure t
:config
(global-evil-leader-mode t)
(evil-leader/set-leader "<SPC>")
(evil-leader/set-key
"s s" 'swiper
"d x w" 'delete-trailing-whitespace))
(use-package evil-surround
:ensure t
:config (global-evil-surround-mode))
(use-package evil-indent-textobject
:ensure t)
(use-package evil-org
:ensure t
:config
(evil-org-set-key-theme
'(textobjects insert navigation additional shift todo heading))
(add-hook 'org-mode-hook (lambda () (evil-org-mode))))
(use-package powerline-evil
:ensure t
:config
(powerline-evil-vim-color-theme)))
I think it needs more key bindings over time…
Use Package
After my setting up an initial install of the Evil mode parts, I
discovered the amazing
use-package. I have come
across it before reading blog posts, but never actually tried
it. After realizing how well it worked, I immediately combed through
my .emacs
file, converting all of my (require 'package-name)
calls
to use-package
forms instead.
Setup
After ensuring the MELPA repos are added and initialized:
;; Add Melpa packages to Repos
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(package-initialize)
The use-package
package can be installed next. I wrapped the
install commands in an unless
, so that when my emacs loads, it
only installs use-package
if it is not already installed.
Afterwards, make sure to (require 'use-package)
. It only needs to
happen during compile, so I have mine in an (evail-when compile ...)
.
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
I keep all of this at the top of my configuration, which works well even when initializing a new computer.
Bye Bye emacs_init.el
When I last had my own custom emacs config, I had to also maintain an
emacs_init.el
file. This was an emacs-lisp script that used a
mapcar
to apply #'package-install
across an ever-growing list of
emacs packages my configuration required. My goal was to have a
script, so that when configuring Emacs on a new system, I could just load
and evaluate the contents of emacs_init.el
, and everything required
for .emacs
would automatically install.
The reality was that it never fully worked. There were always a few
packages that would error, or that I had forgotten to add the last time
I updated my .emacs
file. With use-package
, this might be an issue
of the past, as it allows me to combine my emacs init script with
my configuration files.
Key Bindings
After converting all of my (require 'PACKAGE-NAME)
calls and related
expressions to filled use-package
wrappers, I learned about the :bind
parameter. Instead of manually setting key binds with a setq
,
:bind
takes a list of dotted pairs and binds the function (defined
in the second spot of the pair), to the key sequence stated in the
first spot of the pair.
For example, to setup my preferred ispell
key-bindings, I used the
following :bind
parameter in my ispell
use-package
call:
(use-package ispell
:ensure t
:bind
(("C-c w" . 'ispell-word)
("C-c r" . 'ispell-region)))
This helps to keep the configuration a bit cleaner and organized. The syntax is also straight-forward and easy to remember.
System Specific Load Files
Finally, I moved all my work-specific emacs configuration (setting up
Allegro Common Lisp, defining some helper functions… and anything
Windows specific) into it’s own emacs-work.el
file. With that in it’s
own separate file, I just needed to load
it from my main .emacs
configuration. The only issue with that, is I only want it to load on
my work computer. So, I wrapped it with a nice little handler:
(when (string-equal system-name "LAFAYETTE")
(load "~/.emacs-work.el"))
This works because I don’t name my home computers with the same name
as my work machine. This little tweak worked so well, that I decided
to make another file, emacs-linux.el
, that I could dump my Linux
and/or home specific configuration into. I only load it when on a
GNU/Linux machine:
(when (string-equal system-type "gnu/linux")
(load "~/.emacs-linux.el"))
I’ve really enjoyed the ability to only load parts of my configuration
when a certain condition is met. Breaking down my configuration into
use-specific components seems like a good idea (like abstracting messy
code to smaller functions). Right now, I try to keep my configuration
file partitioned into sections, based on use-case (Writing,
Development, Appearance, etc). However, as I continue to fine-tune my
emacs setup, I think I might break those sections into actual files,
and then load
them from the main config.
The only issue I can see with that is that it can be confusing with
overlapping use-cases. However, I already have to deal with that in a
single configuration (which section to put it in), and my process
of converting everything to use-package
has actually started to
minimize that issue. So it might work…
Next Steps
Now that I have an “Evil
” Emacs setup configured, things should be
returning to business as usually. As I work, I sure there’ll be a
forgotten package here or there that needs to added. However, with
use-package
, that should be a piece of cake, and easy to maintain
from here on out.
Organizing my Emacs config with Org-Babel SQL Intro