Installing and Managing Packages
To follow along with this tutorial, all you need is an existing
installation of Emacs 24, or package.el. I note 24 specifically because if you have
Linux, your distribution might not have an Emacs package that is version 24 or higher.
You can find out your emacs version with the 'M-x emacs-version' in
your Emacs. If you don't have 24, Bozhidar Batsov wrote a great guide
on installing emacs 24.
Conversely, you can install package.el.
Simple add it somewhere to your .emacs.d and load it as shown in part 1.
Text editors tend to be limited in the initial functionality they
provide. Even Emacs, which provides a larger set of base functionality
and features than most, will probably not have everything you
want. Luckily, like most other editors these days, Emacs provides
methodology to extend your text editor by taking code others have written. Vim and Sublime call them
plugins, Emacs calls them packages.
As of Emacs 24, packages management is now included by default. This means you have a way to:
- install packages: M-x package-install <package>
- list all existing packages: M-x list-packages
But we have a couple steps to go until we reach package management nirvana.
For this tutorial, let's add two separate files into our ~/.emacs.d/ directory:
And load .emacs.loadpackages files in your ~/.emacs:
We're going to split our code up into two parts: one file to define
what packages we want to install, and another to load and set up those
Adding packages archives
Emacs 24's packages manager allows the adding of additional package
archives, the places where package.el looks for packages to
install. In your my-packages.el, let's tell Emacs to add some more
; my-packages.el (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t) (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/") t) (package-initialize)
So what are these package archives? Here's some info about them:
- melpa is a package archive managed
by Milkypostman. It's the easiest package archive to add packages
too, and is automatically updated when the package is. The go-to
source for up to date, and the vast majority of, packages. However
it's worth noting that with cutting-edge comes instability, so that
is a risk of stability one should be aware of. It's worth noting I've never been
broken for any package I've installed via melpa, however.
- marmalade is another third-party
package manager. Marmalade tends to be more stable, due to the
requirement that developers explicitely upload new versions of their
I personally use both (and the built-in Emacs 24 package-archive), but
if you don't want to use one or the other, remove the offending
statements from above.
The code above does the following:
- loads the package 'package' via the require keyword
- installs relevant package managers
- initializes the package system so definitions are loaded
Installing and Loading Packages on Startup
Now that we have the package repositories we like, it's time to
install some packages! First, choose a package you'd like to
install. I'm going to install magit, a very nice version
control major mode for git, and yasnippet, a package to easily
parameterize and inject templates as needed (e.g. a java class template).
Remember, you can always find more package by using 'M-x list-packages'
If you wanted to install these manually, all you would have to do is 'M-x
package-install <package>'. However, I believe in reproduceability, so I'm
going to explain a method that will automatically install desired
missing packages on startup.
(To give proper attribution, I adapted this method from snippets in this file
The first step is to define a list of packages you want installed on
startup. In your my-packages.el, after the package archives have been
initialized, let's create a list and store our desired packages in them:
; my-packages.el ; defvar is the correct way to declare global variables ; you might see setq as well, but setq is supposed to be use just to set variables, ; not create them. (defvar required-packages '( magit yasnippet ) "a list of packages to ensure are installed at launch.")
Now that required-packages is defined, we can use it to install some
packages! Let's add a few more lines to install these packages for us:
Add the following to my-packages.el:
; my-packages.el (require 'cl) ; method to check if all packages are installed (defun packages-installed-p () (loop for p in required-packages when (not (package-installed-p p)) do (return nil) finally (return t))) ; if not all packages are installed, check one by one and install the missing ones. (unless (packages-installed-p) ; check for new packages (package versions) (message "%s" "Emacs is now refreshing its package database...") (package-refresh-contents) (message "%s" " done.") ; install the missing packages (dolist (p required-packages) (when (not (package-installed-p p)) (package-install p))))
So what does this code do? Well:
- package-installed-p is from package.el and checks if a package is installed
- packages-installed-p checks if all desired packages are installed
- the unless clause:
- first checks if all packages are installed. If they are, no need to do extra work.
- if not all packages are installed:
- refresh the package indices
- install each non-installed package.
So whenever I want to install a package, I just add it to the list. If
you share your .emacs configuration across machines, or have to start
from scratch, this makes it very easy to build an environment. Even if
you completely blow away your existing packages.
Give it a try! shut down your emacs now and start it back up, and you
should install the magit and yasnippet packages.
Loading and Configuring Packages
So now we have packages installing automatically. How do we use them?
Each package has it's own configuration, so it's best to read the
README or documentation. However, almost all packages require you to
require it first. Let's add a few lines to our .emacs.d/my-loadpackages.el:
; my-loadpackages.el ; loading package (load "~/.emacs.d/my-packages.el") (require 'magit) (define-key global-map (kbd "C-c m") 'magit-status) (require 'yasnippet) (yas-global-mode 1) (yas-load-directory "~/.emacs.d/snippets") (add-hook 'term-mode-hook (lambda() (setq yas-dont-activate t)))
So each package section starts with a "require", which loads a
particular package into the existing emacs environment. This is
required before configuring anything related no that package. Notice
that I also use the require as a section header, defining what package
is related to what configuration.
One thing to note here is that once a package is loaded via require,
it's methods are globally available EVERYWHERE. There's no concept of
importing just for the file in emacs lisp, you just add everything to
this global context. However, most packages use a prefix, (such as
'yas' for yasnippet commands) so it doesn't seem too cluttered.
Here we also see another use of add-hook, but it's different this
time: this time we hook it to a particular major mode. This means that
this particular hook will activate when that major-mode is
activated. This is useful when you want to activate specific behaviour
for when you're editing a particular kind of text (e.g. binding a
shortcut to open up a python interpreter if you're in a python major mode)
As an aside, here's the configuration I'm setting here:
- binding C-c m to magit-status: this is an example of a custom
shortcut for my environment. Wherever I am, I can hit C-c m and see
the status of the git repository I'm in (if I'm in one).
- yas-global-mode: this ensures that yasnippet is activated
globally. Since yasnippet doesn't typically interfere with anything,
and I've found that any sort of text I'm modifying benefits from
snippets, It's a good default to have.
- yas-load-directory: this allows me to load snippets from a specific
location. I have custom snippets I store in there.
- (add-hook 'term-mode-hook...): this is a little hack that needs to
exist. Otherwise, tab-complete doesn't work in Emacs' terminal
emulators such as ansi-mode.
Here's what we learned:
- emacs has a built-in (as of Emacs 24) package management system.
- can install third-party repositories by adding entries to package-archives
- can install packages manually with M-x install-package
- packages can be loaded via (require '<package-name>)
Note: this includes code from part one
(load "~/.emacs.d/my-loadpackages.el") (add-hook 'after-init-hook '(lambda () (load "~/.emacs.d/my-noexternals.el") ))
; ~/.emacs.d/my-noexternals.el ;; Remove scrollbars, menu bars, and toolbars (when (fboundp 'menu-bar-mode) (menu-bar-mode -1)) (when (fboundp 'tool-bar-mode) (tool-bar-mode -1)) (when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) ;; Wind-move (global-set-key (kbd "C-c C-j") 'windmove-left) (global-set-key (kbd "C-c C-k") 'windmove-down) (global-set-key (kbd "C-c C-l") 'windmove-up) (global-set-key (kbd "C-c C-;") 'windmove-right)
; ~/.emacs.d/my-packages.el (require 'cl) (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t) (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/") t) (package-initialize) (defvar required-packages '( magit yasnippet ) "a list of packages to ensure are installed at launch.") ; method to check if all packages are installed (defun packages-installed-p () (loop for p in required-packages when (not (package-installed-p p)) do (return nil) finally (return t))) ; if not all packages are installed, check one by one and install the missing ones. (unless (packages-installed-p) ; check for new packages (package versions) (message "%s" "Emacs is now refreshing its package database...") (package-refresh-contents) (message "%s" " done.") ; install the missing packages (dolist (p required-packages) (when (not (package-installed-p p)) (package-install p))))
; ~/.emacs.d/my-loadpackages.el ; loading package (load "~/.emacs.d/my-packages.el") (require 'magit) (define-key global-map (kbd "C-c m") 'magit-status) (require 'yasnippet) (yas-global-mode 1) (yas-load-directory "~/.emacs.d/snippets") (add-hook 'term-mode-hook (lambda() (setq yas-dont-activate t)))
Next tutorial, we'll talk about writing our own methods and modifying behaviour ourselves.