Grail

Grail loads an .emacs configuration by looking into a directory tree, instead of loading a single monolothic .emacs. There are many good reasons to do this, and some powerful features:

Why ?

Grail is grew out of a tidyconfig like need to re-organize after a .emacs bankrupcy. It has grown beyond organization alone into a comprehensive management of load-path, porting configurations between linux & Darwin, and partial/incremental loading to configure for batch, interactive, gui, and daemon modes.

I wrote Grail simply because I need it. I have Emacs on several different machines and operating systems. I need some elisp loaded on OSX, some on debian, gentoo etc. I need Emacs to work on a TTY or a GUI without barfing, and I love --daemon when I can use it.

The advanced profiles support came out of a need to simply have a single configuration in a tarball/version-control and have all the third party stuff automatically installed when it is not there for some reason. I think stuffing other people’s packages into my version-control is in bad taste, so I needed an install option.

ELPA is the future, and will be in a future emacs (more proof), so I support it as the best way to install third party stuff.

Break it down

Grail replaces your .emacs, and loads your configuration. You put your configuration in the places where grail looks for things. You can start by putting everything into user.el, or make it as fine-grained as you need so emacs always starts correctly.

Examples of the files grail looks for:

Ordering

Grail loads things in a certian order that has been refined over time to keep your sanity. If these places do not exist, they are not placed in load-path. Only what you use ends up in load-path.

2. local/elisp/      The directory containing Emacs libraries created and maintained by the user.
3. dist/             The directory for managing distributed packages
4. dist/elisp/       The directory containing third-party elisp extensions of Emacs
5. dist/elpa         ELPA managed third party elisp.
6. dist{cvs,git,svn} version control managed third party elisp

Third Party Elisp

ELPA and various other ways of installing third party elisp is done by grail-profiles. When you need third party elisp you have to first load it, and second configure it. Grail uses a profile file which has a install/load at the top followed by the configuration.

When the profile is discovered by grail it first installs it if necessary, then it loads it into load-path, and finally it executes the package configuration.

Contact the Author

I have a way of contacting me and looking at other projects on codermattie.

I love squasing bugs ! you find them … I kill them !

Status: 0.4.0 Released: 2011-11-05

This release is significant in that it supports the next generation ELPA package.el. It has been tested against Emacs 23 & 24. It has also been tested successfully on windows finally !

Some small bugs have been fixed as well. This release does not have any serious code churn indicating that the code-base is maturing well.

Status: Resuming Development: 2013-12-08

I stopped work on grail for a while due to not feeling well for a extended period of time.

I have in the past six months or so resumed development. I was previously releasing stable forks. I have not done so again because there is still one issue that I think makes it difficult for others to use.

Basically I want Grail to be async so you can see the installation process and not just hang Emacs, but that really isn’t possible with Emacs.

Getting it to work truly smoothly will require re-coding the install/load/configure procedure as a state machine so that I can chain process termination callbacks into a load/configure sequence.

This is not quite so bad as it sounds since I do something like that in numerous places throughout my config.

Currently I have vastly updated and improved the old code using the old model as a precursor to the final step. It has one quirk. Once the first run with Emacs is completed, it must be re-run to get newly installed packages to load.

I will fix that and then finish with the new model.

If you want to use it now, it certainly works on Linux & Darwin with Emacs24 and dev snapshot, and a large config.

From now on the best way to get updates to to go to the site where I am updating it:

http://lispblivet.sx/emacs-projects.html#grail

It is rough as a web page but I am working alot.

Testing

Emacs24,Emacs Snapshot on Linux & Darwin

Download

I have a section for grail in my Emacs projects. The links to the files are there.

http://lispblivet.sx/emacs-projects.html#grail

Install

These install instructions assume you already have a .emacs configuration.

1. choose a location where your Emacs configuration will live. This directory will be called $USER_ELISP.

2. download the grail files from the download links above to $USER_ELISP

3. copy your .emacs to $USER_ELISP/user.el

4. copy/extract the customize generated settings to $USER_ELISP/customize-settings.el

5. make link from ~/.emacs → $USER_ELISP/grail.el

you can now start Emacs with Grail loading your config

6. start emacs like this:

USER_ELISP=<where you put grail and your config> emacs

7. Look at the diagram of USER_ELISP in the next section and organize your configuration to your taste.

A diagram of USER_ELISP

This is a simple diagram of what the USER_ELISP directory looks like when all of the Grail recognized files and directories are in place.

When a directory has a (++) next to it Grail will add any sub-directories beneath that directory, as well as the directory itself to load-path.

The diagram also shows which modes load the special files. As you can see only elisp.el, and gui.el are truly special in that they are loaded differently from the others.

The files like commands.el, and keys.el are opportunities to organize, they are not required.

display.el and gui.el are delayed in --daemon mode. display.el is loaded before the first frame (TTY/GUI) is created, and gui.el after the first GUI frame is created.

This delay insures that the GUI is actually loaded before the user’s customizations are loaded.

|-- grail.el                  ;; grail files
|-- grail-fn.el
|-- grail-profile.el
|
|-- customize-settings.el      ;; where customize scribbles
|
|-- elisp.el       |BATCH,all| ;; A library of Elisp functions loaded in both batch and interactive mode.
|
|-- user.el        |TTY,GUI|   ;; user configuration of Emacs. All the stuff built into Emacs Tramp,VC,Ediff,...
|-- interface.el   |TTY,GUI|   ;; general interface issues (in mine turning off the menu bar etc...)
|
|-- commands.el    |TTY,GUI|   ;; The user's collection of commands.
|-- keys.el        |TTY,GUI|   ;; The user's key bindings.
|
|      *** delayed for daemon mode ***
|-- display.el     |TTY,GUI|   ;; Configuration for a TTY or graphical frame.
|-- gui.el         |GUI|       ;; Configuration for a graphical frame.
|      *** delayed for daemon mode ***
|
|-- customize-settings.el   |TTY,GUI| ;; Settings written by customize and Emacs.

|-- dist
|   |-- elisp (++)
|   |   `**Downloaded Elisp** ;; download Elisp files, and packages with directories are found here.
|   `-- elpa                  ;; ELPA maintained packages are installed here.
|
|-- local
|   |-- elisp (++)            ;; the user's Elisp is searched for in local/elisp.
|   |   `**your Elisp**
|   |-- emacs                 ;; modified copies of files distributed with Emacs.
|   `-- profiles              ;; profile configuration modules are found here.

The Profiles Feature

Profiles allow configuration snippets that depend on third-party code to download the third-party code, load, and resume the startup of Emacs.

Here is an example of a profile from my configuration that loads all of my lisp programming settings.

(grail-load 'mic-paren (grail-define-installer "mic-paren"
                         "file"
                         "http://www.emacswiki.org/cgi-bin/emacs/download/mic-paren.el"))

(grail-load 'quack     (grail-define-installer "quack"
                         "file"
                         "http://www.neilvandyke.org/quack/quack.el"))

(grail-load 'slime     (grail-define-installer "slime"
                         "cvs"
                         ":pserver:anonymous:anonymous@common-lisp.net:/project/slime/cvsroot"))

(setq
  paren-showing t
  show-paren-style 'parenthesis
  show-paren-delay 1
  paren-sexp-mode 'match)

When I copy my configuration to a new machine I simply copy this “profile” file and start Emacs. When Emacs starts Grail detects that the packages are missing before the configuration bits runs. Grail installs the packages, adjusts load-path as needed, and attempts a second load of the package.

It is almost this simple ! profiles are not automatically loaded just because they are in the profiles directory. I also place this command in one of the special files grail loads.

(use-grail-profiles 0 "template" "lisp" "code-formatting" "sql")

This is in a file automatically loaded by Grail. It is a list of the profiles that Grail should load. The first value is a digit indicating the loading priority. 0 is the highest priority while higher numbers are lower priorities. The profiles are loaded in highest to lowest priority.

All of the profiles are loaded at the very end of the startup process so the configuration bits in the profile files can use the definitions from everything loaded previously.

Here are some examples of my profiles:

Here is the documentation string for grail-define-installer

(defun grail-define-installer ( name type &rest url-list )
  "grail-define-installer NAME TYPE &rest URLS

   define a installer for a package NAME.

   The type of the installer indicates the format of the URL.

   TYPE is the format of the URL for handling things like
   compression,archives, and RCS systems.

   recognized TYPE's : file, tar:bz2, tar:gz, cvs svn git

   download a plain elisp file: (grail-define-installer \"bob\" \"file\" \"URL\")
   download an tar.bz2 archive: (grail-define-installer \"bob\" \"tar:bz2\" \"URL\")
   cvs checkout:              : (grail-define-installer \"bob\" \"cvs\" \"pserver\")

   Most of the time a single URL suffices. Many packages are a
   single elisp file, or a single tarball.

   Other packages such as icicles are several elisp files, or
   possibly several archives.

   In this case a list of cons pairs can be given as the
   URL. When this happens NAME becomes a sub-directory they are
   installed to, and the files a list of (name . url) pairs.

   (grail-define-installer PACKAGE \"file\"
    '(\"foo.el\" . \"URL\")
    '(\"bar.el\" . \"URL\")

    this would install as:
    PACKAGE/foo.el
    PACKAGE/bar.el
  "

Q&A

Q: What should I set ‘custom-file’ to, i.e., where should I store my customizations?

A: As of the grail-0.1.3 Grail handles customizations.

   It looks in the variable "grail-settings-file" which points to 
   USER_ELISP/customize-settings.el by default.
   It will change both "user-init-file" and "custom-file" to point at your
   "grail-settings-file" when grail starts.
   If you have used Grail and customize before 0.1.3 it has likely
   written customize settings to grail.el itself which is not fatal,
   but not good.
   To upgrade to grail-0.1.3 you need to edit grail.el, or whatever
   other files have these customize settings, and migrate them to
   customize-settings.el
   I will ponder a migration tool if I can come up with something safe.