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 Evil 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 machine — 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 : use-package , general.el , which-key and ivy . They are the backbone of my new setup.

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 fast .

The following code loads the package which-key, and make sure it is loadable. If not, it downloads it, thanks to key :ensure keyword.

(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.

:init (which-key-mode)

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 use-package .

:diminish which-key-mode

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 call the (ranger) function. So I put (ranger) in the list of commands that will trigger the loading of ranger .

(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 (deer) to 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 use-package and 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 prefix 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 C-SPC then l , it calls avy-goto-line .

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, SPC ar 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 the :ignore keyword when the key-press is only a prefix, and you want to describe the prefix via which-key .

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, general.el being 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 developper build an ecosystem of tools based on its variation of ido . Those packages are ivy , counsel and swiper . They represent a great alternative to the somewhat clumsy helm ecosystem.

ivy extend my mind inside emacs

Just like helm or ido , 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 associated package counsel .

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 ivy and counsel :

(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 files . 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.

Conclusion

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.