Spacemacs is a great starter kit. It is the only kit that got my attention. I have been using it for one year or so. I know most of its most useful commands. I like the plug-and-play feeling of its layer system. I like the laziness of its packaging system. I like how the devs build a great terminal experience inside emacs. I like how it abstracts Evil1 from its users.
But I recently grew tired of its clumsiness. It took like seven or eight second to load. I tried to remove some configuration layer. I removed chunks of config I did not need. At its best, Spacemacs took — on my machine2 — seven long seconds to load. I gave me the feeling that I did not need most of the full blown spacemacs distribution. Plus I wanted to understand how to setup my own emacs. I wanted to tweak it. I wanted to get my hands dirty.
During my year in the spacemacs world, I discovered four awesome packages :
ivy. They are the backbone of my
I only need those four packages to build a good spacemacs experience.
use-package made my emacs fast
use-package is a package by the current maintainer of emacs. I use it to load
packages lazily. They will not be loaded unless I call them, or one of
my packages call them. It make the startup super fast3.
The following code loads the package which-key, and make sure it is loadable. If
not, it downloads it, thanks to key
(use-package which-key :ensure t
I use the
:init keyword to execute bits of code before the package is loaded.
The following will enable
which-key in each buffer.
I use the
:config keyword to customize the module to my convenience. Those
bits of code are executed after the package is loaded.
:config (which-key-setup-side-window-right-bottom) (setq which-key-sort-order 'which-key-key-order-alpha which-key-side-window-max-width 0.33 which-key-idle-delay 0.05) )
To avoid a cluttered mode-line, I use the
diminish keyword of
I could also use the following syntax, to replace the
WK in the mode-line with
:diminish (which-key-mode . "Ꙍ")
Here I showed you how I use
use-package to load a package that is enabled
globally at startup. But
use-package has many option to make sure the package
is not loaded if nobody needs it. I use the
:commands keyword to load the
package when a command in the list of command is called.
For example, if I want to use the
ranger package, I do not need it until I
(ranger) function. So I put
(ranger) in the list of commands that
will trigger the loading of
(use-package ranger :ensure t :commands (ranger) :bind (("C-x d" . deer)) :config (setq ranger-cleanup-eagerly t) )
use-package also provide the
:bind keyword. I use it to describe the list of
commands that will trigger the loading of my package, and the keybindings that
I want to associate with the command. In the previous example, I mapped
C-x d. So, unless I call
(ranger) before typing
C-x d, the
ranger package will not load.
This is the magic of use-package.
general.el made my evil shine
General.el is the new evil-leader black. It makes it easy to implement leader
keys, of any length you want. It also has nice integration with
which-key. Its primary use is in combination with
evil, but you can also
use it with bare emacs.
(use-package general :ensure t :config (general-evil-setup t) (general-define-key :states '(normal insert emacs) :prefix "C-SPC" :non-normal-prefix "C-SPC" "l" '(avy-goto-line) "a" 'align-regexp ) (general-define-key :states '(normal motion insert emacs) :prefix "SPC" "ar" '(ranger :which-key "call ranger") "g" '(:ignore t :which-key "Git") "gs" '(magit-status :which-key "git status") ) )
The previous chunks load the
general package at startup. This one is not
lazily loaded. It uses
(general-define-key) to define keys that are under the
C-SPC. When the evil-state is not normal, ie when I am in insert or
visual mode, the prefix is also
C-SPC, but I can set it to something
different. So when I press
l, it calls
The next chunks is all it takes to setup a Spacemacs-like interface to my
favorite commands using the space bar as a prefix. Like in spacemacs,
calls ranger. Notice the
:which-key keyword. Use it to describe your
keybindings. The string I use will be displayed by the
which-key package. Use
:ignore keyword when the key-press is only a prefix, and you want to
describe the prefix via
which-key will make your emacs friendly
The obvious benefit of spacemacs to me is its discoverability. Press a key, read the description of the prefix, press another key, etc…
which-key is a package that prints out a buffer of all the keybindings
currently assigned to the prefix you type. In the previous example, if I type
C-x, then a buffer prints out:
It is a listing of all the keyboard shortcut starting with
C-x. But what if I
want to know what is behind the
RET keypress ?
which-key provide a way to
describe a prefix.
(which-key-add-key-based-replacements "C-x RET" "coding system - input" )
So now when I press
C-x, I see:
Those three packages all belongs in the spacemacs universe,
only an upgrade over
evil-leader. The spacemacs dev chose to use
helm as a
default “incremental completion and selection narrowing frameworks”. But
recently, a proficient and prolific emacs package developper5 build an ecosystem
of tools based on its variation of
ido. Those packages are
swiper. They represent a great alternative to the somewhat clumsy helm
ivy extend my mind inside emacs
ivy is a “generic completion framework”. It shines
at being unobtrusive and really fast. I was really surprised by the fact that I
could reimplement most of my most used spacemacs commands on top of
ivy or its
ivy-mode ensures that any Emacs command using completing-read-function uses ivy for completion. Counsel takes this further, providing versions of common Emacs commands that are customised to make the best use of ivy.
Here is my
(use-package) declaration for
(use-package ivy :ensure t :diminish (ivy-mode . "") ; does not display ivy in the modeline :init (ivy-mode 1) ; enable ivy globally at startup :bind (:map ivy-mode-map ; bind in the ivy buffer ("C-'" . ivy-avy)) ; C-' to ivy-avy :config (setq ivy-use-virtual-buffers t) ; extend searching to bookmarks and … (setq ivy-height 20) ; set height of the ivy window (setq ivy-count-format "(%d/%d) ") ; count format, from the ivy help page ) (use-package counsel :ensure t :bind* ; load counsel when pressed (("M-x" . counsel-M-x) ; M-x use counsel ("C-x C-f" . counsel-find-file) ; C-x C-f use counsel-find-file ("C-x C-r" . counsel-recentf) ; search recently edited files ("C-c f" . counsel-git) ; search for files in git repo ("C-c s" . counsel-git-grep) ; search for regexp in git repo ("C-c /" . counsel-ag) ; search for regexp in git repo using ag ("C-c l" . counsel-locate)) ; search for files or else using locate )
swiper is an
isearch replacement based on ivy. It is really really fast. I
have tried it on huge files6. It still is really really fast. I have the
feeling it is much faster than
helm-swoop, though I did not measured it. I
bind it to
C-s, the default keyboard press to isearch.
Here I showed you how I used those four packages and their ecosystem to build myself a great spacemacs-like experience. In the next post, I want to spend some time on helping you build your own experience of emacs. I will use those packages to describe you how you could build yourself a great emacs environment, using modern tools.
- Evil is The vim emulation inside emacs. It makes emacs behave exactly as vim. Try it if you want to keep your carpal tunnel. [return]
- A 2011 MacBook Pro with 16G of RAM and a Samsung SSD. [return]
- Like one-second fast. [return]
- Yes, you can and should use unicode. [return]
- See its github profile here. [return]
- I have tried it, just like the maintainer, by copy-pasting org.el multiple time in itself. The file was like 1G bytes huge. Swiper did not tremble. [return]