Configuring Emacs from Scratch - use-package
(You can read this post on Medium.)
This is the third part of a series on “Configuring Emacs from Scratch”. You can read the first part here and the second part here.
In the last two parts, we customized some defaults of Emacs. We also installed two packages and customized their default behavior. In this part, we will organize our configuration and make it portable using use-package.
After the first two parts, our init.el
looks like this:
What problems do you see in this configuration? There is one major and one minor problem (and there must be many which I have missed).
-
This setup is not portable.
-
The structure of code is too flat.
This setup is not portable
We cannot just take our init.el
from one computer to other and then expect to have our Emacs setup portes. What do you think will happen when you copy your init.el
to a new computer?
*What is our code assuming?
*Is our code telling Emacs to install spacemacs-theme
and company
? No!
We are assuming that the packages - spacemacs-theme
and company
will already be there on all computers.
When you open Emacs on a new computer, it will only have the default Emacs packages. So the load-theme call in our init.el
will fail. Enabling company-mode
will also fail since there is nothing called company-mode
at this point. So all your configuration code related to spacemacs-theme
and company
will either fail or will be ineffective.
An example where it will not fail but will be ineffective is when you set spacemacs-theme-comment-bg
to nil
. This call will not fail. It will just create a variable. But it will be ineffective since there is no package which uses that variable.
So the conclusion is - There is no way to port this setup without manually installing all the packages.
The structure of the code is too flat
Currently, our configuration code is not grouped based on packages. You can always group it manually by keeping all configurations for a package together. But that can get hard to maintain. As you go on adding packages and customizing little things here and there, it is easy to spill configuration of a package all over init.el
.
This might not even feel like a problem at this point in time. But as our setup evolves, this will be a big problem for managing the setup.
There are many different solutions for the above two problems. The natural way of solving the first problem will be to maintain a list of packages that we use and check if those are installed. If some package is not installed, install it. Something like this:
Note: In Elips any function ending with a -p
is a predicate.
This solution works perfectly well. But there is a very elegant solution for this (which happens to solve the second problem as well). It is called use-package.
Use-package
use-package is an Elisp macro written by John Wiegley. It simplifies and groups together configuration for packages. Install use-package by pressing: (By now, you should know how to install a package.)
A common use-package declaration looks like this:
Note: Any word, preceded with a :
is called a keyword
in Elisp. You can consider keywords as being similar to strings, but with a different purpose and presence.
Let’s see how would a use-package declaration look for company
. Our current config for company
is:
With use-package, it will look like this:
Here we are saying-
-
This is a use-package declaration for the package
company
. -
In
company-active-map
, bindC-n
tocompany-select-next
andC-p
tocompany-select-previous
. Notice the minimal syntax here vs thedefine-key
call. -
After
company
is loaded, setcompany-idle-delay
to0.3
and enable company mode everywhere.
Now all the configuration related to company
is naturally grouped together in the use-package
declaration. Next time when we want to make some changes to company
, we will come to this declaration and add our code. This way, our setup will always be well grouped. So use-package has solved our second problem.
But what about the first problem? Will use-package download the missing packages?
Yes, it will. You just have to add :ensure t
to the declaration. For example, look at this:
Note: Magit is an super awesome git client for Emacs that you must use.
:ensure t
will make sure that magit
is downloaded if it is not there. Also, look at the bind
syntax here. When you want to make a global binding (unlike the bind
in company
, which was local to company-mode-map
), the syntax is even more minimal. You just have to specify (key-binding . command)
pairs. :)
use-package has solved both of our problems! :)
Note: use-package has many more useful (and very well thought of) keywords. I recommend going through the README.md.
Note: Even though use-package is a handy macro, we must know what is going on under the hood when we use it. Since it is just a macro, you can expand it yourself and see what is going on. Read about macro expansion here.
*So is our setup fully portable now? *Nope! There is still one small problem. use-package is not there in Emacs by default and you cannot use use-package to install itself. :P
So to make our setup fully portable, we need to check if use-package is installed and if it is not, we need to install it.
Now our init.el
will look something like this:
Here are a few packages (along with their configurations) that I think every Emacs setup should have:
Conclusion
In this three part series on configuring Emacs from scratch, we have seen,
-
The Emacs way of text editing.
-
Using the Help system to know what is going on.
-
Tweaking the defaults of Emacs.
-
Installing packages.
-
Organizing your setup.
-
Making your setup portable.
While doing this, we have seen how customizable Emacs is! :)
I have not covered even a percent of the capabalities that Emacs has. Org-mode in itself is a topic of another (huge) series of posts. And there are many more packages which make Emacs special and unique.
But I think we have covered enough to be able to proceed on our own now. The key is to know how to use Emacs’s help system. (Sorry for repeating this over and over again, but you will realize the power and convenience of Emacs’s help as you use it.)
You can find my Emacs setup here. Feel free to borrow things. If you find better ways, please send pull requests. :) (It is strongly recommended to have your Emacs configuration under version control.)
I must mention and thank Narendra Joshi and Vedang Manerikar as I’ve always stolen (and look forward to stealing) things from their Emacs configurations.
Tips on “Evolving your Emacs setup”
The strategy I use to improve my Emacs setup is called UFFL. (Honestly, only I call it UFFL.)
Use - Find painpoints - Fix - Loop
As you would have guessed, I have totally made this up just to make it analogous to REPL. But it does describe the strategy well. :)
After making an edit to my configuration, I use it for a few days for my day to day tasks. I often find some painpoints (i.e. things that can be improved / automated / achieved in lesser number of key strokes) while using it. Then I find solutions to those problems. Usually, I try to solve the problems myself by finding the right configuration parameters or by writing some Elisp. Then I check if there are solutions on Emacs Stack Exchange (or anywhere on the Internet). In most of the cases, solutions from the Internet are better and more elegant than my own solutions. But I still recommend finding/writing your own solution before looking up online, so that you get better at Elisp and at the Emacs way of thinking. :)
And this goes on forever …