Emacs is a great environment to build a text editor. Being a really old piece of software, searching the internet does not always lead to the best or more recent results. My goal is to help you build an editor inside Emacs using the best tools for the job, with modern tools and well-crafted packages.

In a previous post, I described the tools I needed to build myself a great spacemacs-like1 experience inside emacs. In this post, I want to explain the process of building it in more details. I hope it serves you in building a cool editor the way you like it.

Emacs proficient reader should skip this part and jump directly to the use-package part here. Those that already know about use-package should jump here, where I talk about ivy, swiper, counsel and general. Those that do not want to read all my strange french-english prose can and should jump directly to here. I have put up a recipe to a modern Emacs experience.

Emacs is a text editor and a programming environment built on top of a programming language, just like Python or Java, called emacs-lisp. The text editing abilities of a bare Emacs distribution are decent, but today most Emacs users extend it through other pieces of software called modules or packages. They are also written in emacs-lisp, often by user of Emacs that became frustrated by a lack of feature or thought they could do better. The result is a big ecosystem of emacs-lisp packages, of which you can get an idea at melpa.org. Anybody can download it and use it to extend the functionnalities of emacs.

One of the main strength of Emacs is its extensibility and flexibility. As our first step, we are going to learn how to configure it using basic emacs function.

Getting Emacs ready for the job

Once you have installed the most recent version of Emacs using your beloved package manage and opened it, Emacs will create a directory in your $HOME directory called ~/.emacs.d. When Emacs start, it reads a file in this directory called ~/.emacs.d/init.el, and execute any emacs-lisp command it finds in it. We are going to use this file to customize emacs to our liking.

As a version control adept, I have symlinked init.el to a dotfile repository under VC.

When inside Emacs, press C-x C-f (meaning control-f then control-f), the emacs command to open a file. Emacs will prompt you for a file to open, and type ~/.emacs.d/init.el. Emacs being really old, some of its default configuration are somewhat — er — mysterious and mystical. We are going to use init.el to introduce some sane defaults. Paste the following chunks using C-y.

(setq delete-old-versions -1 )		; delete excess backup versions silently
(setq version-control t )		; use version control
(setq vc-make-backup-files t )		; make backups file even when in version controlled dir
(setq backup-directory-alist `(("." . "~/.emacs.d/backups")) ) ; which directory to put backups file
(setq vc-follow-symlinks t )				       ; don't ask for confirmation when opening symlinked file
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)) ) ;transform backups file name
(setq inhibit-startup-screen t )	; inhibit useless and old-school startup screen
(setq ring-bell-function 'ignore )	; silent bell when you make a mistake
(setq coding-system-for-read 'utf-8 )	; use utf-8 by default
(setq coding-system-for-write 'utf-8 )
(setq sentence-end-double-space nil)	; sentence SHOULD end with only a point.
(setq default-fill-column 80)		; toggle wrapping text at the 80th character
(setq initial-scratch-message "Welcome in Emacs") ; print a default message in the empty scratch buffer opened at startup

Place your cursor after the closing paren of the first line and press C-x C-e. It will execute the previous bits of code. setq is an emacs-lisp word meaning “set the following variable to the following value”. For the first line, we could translate in plain english to “set the variable delete-old-versions to -1”.

Now save the init.el modifications by pressing C-x C-s, and quit Emacs by pressing C-x C-c. Restart it. Now press M-x (depending on your OS, it should corresponds to Alt-x) and describe-variable, then delete-old-versions. It should open a buffer with the documentation of the variable, with a line saying “Its value is -1”. So basically when Emacs started up, it evaluated the lines of code in ~/.emacs.d/init.el. Now press M-x describe-key and press C-e. It should print a buffer describing the function attached to the keybindings C-e

In those simple exercises, we covered very important Emacs notion :

  1. Every command is bound to a function. Those function are, most of the time, defined in emacs-lisp. Some very important function are defined in C for performance.
  2. You learned that Emacs has a very thorough documentation describing variables, functions, keybindings…
  3. You learned to modify a variable using emacs-lisp.
  4. You learned how Emacs execute code at startup, and we can leverage that to customize it to our liking.

Introduce structure in your config : use-package to the rescue

The emacs-lisp package archive with wich you can interact at melpa.org has, at the time of writing 3 291 packages. The abundance of modules sometimes lead to something that emacs users call Emacs bankruptcy: a state in which the user does not understand its own Emacs configuration.

I give up. During the past 6 years of my emacs career, my emacs configuration file grew to embarrassing levels. As of this morning, it is well over 1000 lines and is a looming burden of disorganization. Startup time is poor, customizations exist for languages that I don’t use anymore (ahem, > csharp-mode), and it has been this way for too long… —— RyanMcGeary, 2007

To prevent this, John Wiegley, the current emacs maintainer put up a great package called use-package. So, as our second step, we are going to set up use-package and use it for the first time. This “meta”-package is a package to manage other packages and the way they interact. Put the following lines in your ~/.emacs.d/init.el.

(require 'package)

This line basically says to Emacs make available any command present in the package module.

(setq package-enable-at-startup nil) ; tells emacs not to load any packages before starting up
;; the following lines tell emacs where on the internet to look up
;; for new packages.
(setq package-archives '(("org"       . "http://orgmode.org/elpa/")
                         ("gnu"       . "http://elpa.gnu.org/packages/")
                         ("melpa"     . "https://melpa.org/packages/")
                         ("marmalade" . "http://marmalade-repo.org/packages/")))
(package-initialize) ; guess what this one does ?

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package) ; unless it is already installed
  (package-refresh-contents) ; updage packages archive
  (package-install 'use-package)) ; and install the most recent version of use-package

(require 'use-package) ; guess what this one does too ?

Now the best way to learn how it works is by reading its documentation. Nah. Let’s use it first, read then. Restart emacs and put the following line in your init.el, then go to the end of line (C-e) and press C-x C-e.

(use-package general :ensure t)

It should check for the general package and make sure it is accessible. If not, the :ensure t part of the previous chunks tells use-package to download it and place it somewhere accessible, in ~/.emacs.d/elpa/ by default2.

Now every function in the general package is available to you. We will now use the same use-package statement to customize the general package. We need the :config keyword of the use-package macro to do just that.

(use-package general :ensure t
  (general-define-key "C-'" 'avy-goto-word-1)

The third line said “bind to the C-' press the function avy-goto-word-1”. It means we need the avy package. So let’s use use-package again to download and load the avy package.

(use-package avy :ensure t)

But then we do not need this package right when we start Emacs. It can wait until we first call avy-goto-word-1 or any other command from the avy package. So we are going to put this command in the list of command that triggers the loading of the avy package. We use the :commands keyword to do that.

(use-package avy :ensure t
  :commands (avy-goto-word-1))

So now when we start Emacs, the avy package is not loaded. But when we first press C-', it will call avy-goto-word-1 and trigger the loading of the avy package.

Use-package has all kinds of tricks to make sure no code is executed or loaded before it is needed. You really need to check out use-package on your way to mold Emacs to your liking.

Move in Emacs : the abo-abo way

In Emacs as in all text editor, you move more than you type. You move between buffers, ie text files loaded into memory. You move between lines. You move between sentences. You move between semantics unit. You move between files. You search for files. You search for text. You search for regexp. You search for projects.

It really helps to have a uniform interface to the most common commands you call.

One of the most prolific Emacs-package developper that I know of is called Oleh Krehel; abo-abo on Twitter3. During the past two years, he developped an ecosystem around a completion framework that he wrote called ivy. This ecosystem is composed of three packages called ivy, counsel and swiper.

Counsel allow you to find recently visited files, to switch between buffers, to search for a string in the current git directory, to search for a file in the current git directory, to search for Emacs function, to search for system applications to open, to search for music in rythmbox, to … . Well, you get the idea. Swiper allow you to find text really really quickly inside an Emacs buffer.

Ivy proposes completion candidates to the two other, and to many other Emacs function that needs completion and narrowing. You may have heard of another ecosystem centered around Helm. The spacemacs dev chose to use Helm as a central tool, but I can assure you that you will not regret chosing the Ivy way. It is really really fast, really well thought out and really convenient to use.

So now we have a ton on function to bind, and still no way to make that easy. But do we ?

Bind in Emacs : the general way

Recently, a growing user base of Emacs user started to use Evil, a vim emulation built on top of Emacs command. It works just flawlessly. When they did, they developped some ways to bind keys to functions like in Vim. One of the most successful solution to this is evil-leader. And then another Evil user by the pseudo of noctuid created a package called general.el4. Of all the way I know to define keys in Emacs, this one is the most versatile and the simplest solution to defining keybindings.

There is many ways to define keybindings in general.el. Since they are all constructed around general-define-key, it is the most flexible. So let’s use that to bind some keys.

  ;; replace default keybindings
  "C-s" 'swiper             ; search for string in current buffer
  "M-x" 'counsel-M-x        ; replace default M-x with ivy backend

This one is pretty simple. It binds C-s to swiper and M-x to counsel-M-x. Those two keys are probably amongs the two most used keybindings in Emacs. But General allows more complex solution to keybindings definition. Let’s say we want all of our personnal keybindings bound to C-c XY, where XY is a combination of our choice. We can define a :prefix.

 :prefix "C-c"
 ;; bind to simple key press
  "b"	'ivy-switch-buffer  ; change buffer, chose using ivy
  "/"   'counsel-git-grep   ; find string in git project
  ;; bind to double key press
  "ff"  'counsel-find-file  ; find file using ivy
  "fr"	'counsel-recentf    ; find recently edited files
  "pf"  'counsel-git        ; find file in git project

Now C-c b switches buffer using Ivy. And C-c f then f finds files. And C-c f then r find recent files. Now we can see a pattern here: we just placed all command related to finding files under a C-c f prefix. It would be great if we could know when we press C-c what the f corresponds to.

But hey it is Emacs. There is a package for it. It is called which-key. So guess what ?

(use-package which-key :ensure t)

So now when we press C-c, a nice buffer shows up that pressing b will execute ivy-switch-buffer. But what does it show for f ? “+prefix”. We can do better. We can indicate to Which-key that C-c f related functions corresponds to file related operations.

(use-package which-key :ensure t
  "C-c f" "file"
  "C-c ff" "find file"
  "C-c fr" "recently edited"
  "C-c p"  "project"))

Execute this code with C-x C-e as usual. Now press C-c, and see how much which-key is awesome. Never forget a keybinding. Very easy on beginners. Very swift. Very clean. Does it ?

There is some kind of code duplication here. We define it using General, and describe it using Which-key. In fact we can do both in the same statement, using Which-key integration to General.

 :prefix "C-c"
 ;; bind to simple key press
  "b"	'ivy-switch-buffer  ; change buffer, chose using ivy
  "/"   'counsel-git-grep   ; find string in git project
  ;; bind to double key press
  "f"   '(:ignore t :which-key "files")
  "ff"  'counsel-find-file
  "fr"	'counsel-recentf
  "p"   '(:ignore t :which-key "project")
  "pf"  '(counsel-git :which-key "find file in git dir")

Evaluate this code. Press C-c. Same output as before. See how General is great ?

Meeting our goal: build yourself a great Spacemacs-like experience

For Evil users out there, General also has nice integration with Evil states. It means that we can easily define keybindings to match Spacemacs design styles. And yet we retain the ability to build the editor we want. That is what we came to Emacs in the beginning.

Check out what this chunk does.

(use-package general :ensure t
   :states '(normal visual insert emacs)
   :prefix "SPC"
   :non-normal-prefix "C-SPC"

    ;; simple command
    "'"   '(iterm-focus :which-key "iterm")
    "?"   '(iterm-goto-filedir-or-home :which-key "iterm - goto dir")
    "/"   'counsel-ag
    "TAB" '(switch-to-other-buffer :which-key "prev buffer")
    "SPC" '(avy-goto-word-or-subword-1  :which-key "go to char")

    ;; Applications
    "a" '(:ignore t :which-key "Applications")
    "ar" 'ranger
    "ad" 'dired))

When Evil is in normal or visual state, the prefix is SPC, as in Spacemacs. When Evil is in insert or emacs state, the prefix is C-SPC. We can define some key under direct access, describe them using Which-key. We can then define prefix easily, using the :ignore t keyword. See how close we are from Spacemacs ?

So then why not just use Spacemacs and be done with it ? Well, I like the SPC prefix thing too much to let the Spacemacs dev decide for me what keybindings must refer too. I want to make my own Emacs. I want to be able to define :prefix easily. I want to understand what Emacs does, without having to read the entire Spacemacs code base. I want an editor that I can customize to its inner deepness, without being hit by design choices I did not make.

And then Spacemacs has one major drawback to me: it is very Qwerty-keyboard oriented. It means that when you use another keyboard layout, you make some weird movement just to accomodate Spacemacs keybindings.

A recipe for a modern Emacs experience

I have put up a recipe to build a Spacemacs-like Emacs. It is based on what I have done systematically, to build a reasonable and very usable emacs to me.

  1. Spot a package that seems interesting.
  2. Install it using use-package and its :ensure t keyword.
  3. Use it for an hour or two.
  4. Determine the functions you need.
  5. Create autoloading for it using use-package abilities to deferred loading.
  6. Create a keybinding for it using general, under the :prefix you like. Use SPC to look like Spacemacs.
  7. Describe it using which-key or using the :which-key keyword of general definition.
  8. There is no other step. Use your package.

I mean, really. You only need those seven steps. You need use-package, general, which-key. And finally you also need abo-abo packages. They are just too awesome.

  1. Spacemacs is an editor build on top of emacs that is gaining more and more traction among programmers. [return]
  2. Guess what ELPA means ? [return]
  3. Go on and follow him. You won’t regret it. [return]
  4. Check it out here. [return]