Refactoring Configurations

I felt my init.el file was getting too bloated, so I ended up doing a fair amount of refactoring on it. I moved essentially all the code from init.el into a few directories I made in .emacs.d. Structuring your customizations is pretty important if you ever either need to go back to change them or find them to suggest to others; I do both of these a fair amount, so I spend a fair amount of time organizing my files. I probably ended up erring on the side of too many horizontal files, but I think it should be OK for now.

My .emacs.d directory now has four main elisp directories: customizations, major-modes, minor-modes, and utilities. It also has temporary information, documentation, Clojure, and hopefully everything I need to just be able to check it out and have my full working setup. The customizations and utilities directory are currently flat; They contain small files described for what they modify or are for. For example, the Ibuffer customizations I recently suggested are in ibuffer.el. This does sometimes pose organizational problems; Should changing an variable customizing a minor-mode on entering a major-mode be a customization of the minor-mode or major-mode? I currently go for the major-mode, but this could change if I ever have problems finding anything.

Major-modes and minor-modes contain precisely what they describe; All the major and minor modes I have downloaded. Packages that modify other major modes, such as dired+, do not go in these directories; they still go in the customizations file. These two directories can be arbitrarily nested - I just put the modes in however they are distributed.

After moving all the customizations out of init.el, I had the following left:

(let ((default-directory "~/.emacs.d/"))
  (add-to-list 'load-path default-directory)
  (normal-top-level-add-subdirs-to-load-path))
 
(defun load-directory (dir)
  (mapcar '(lambda (x)
             (load-file x))
          (directory-files dir t "\\.el$")))
 
(load-directory "~/.emacs.d/customizations/")
(load-directory "~/.emacs.d/utility/")

The first let expression is a simplification of something I blogged about a while ago; It will add all subdirectories of ~/.emacs.d/ to the load-path; this is necessary so that I don’t have to do manual manipulation of the load-path.

The second function is one I wrote to support my refactorings. It will load every elisp file in a directory. It doesn’t support subdirectories, but this wouldn’t be too hard to add if I ever need it. I then just load up my customizations and utility functions and am good to go. I highly recommend doing something similar to this; Splitting your customizations from one big file and aggregating similarities makes it much easier to manage your configuration.

Tags: , ,

5 Responses to “Refactoring Configurations”

  1. Rafal says:

    It’s a matter of taste. 2 years ago I did a splitting of my .emacs file but after some days I come back to a single file because many times I had problems finding customizations for specific libraries. I made nice comments in my .emacs file and I can easily jump to places I need with C-s. My emacs file has over 7000 lines and I had no problems to manage it so far.

  2. Phil Hudson says:

    I have this, with some macros for facilitating host- and OS-specific customizations:

    - .emacs.d
    -- lisp
    --- mode1setup.el
    --- mode2setup.el
    --- os1
    ---- mode1setup.os1.el
    ---- mode2setup.os1.el
    --- os2
    ---- mode1setup.os2.el
    ---- mode2setup.os2.el
    --- host1
    ---- mode1setup.host1.el
    ---- mode2setup.host1.el
    --- host2
    ---- mode1setup.host2.el
    ---- mode2setup.host2.el
    -- site-lisp
    --- nxml
    --- org
    --- dvc
    --- traverse
    --- etc

    Easily extensible to other kinds of per-something customizations: DNS domain, window system, processor architecture… haven’t needed any of those myself yet.

  3. Phil Hudson says:

    How about:


    (defun load-directory (dir)
    (mapc 'load-file (directory-files dir t "\\.el\\'")))

    * mapc: for side effects only, doesn’t accumulate results (unlike mapcar).
    * No lambda wrapper required for load-file, since it takes exactly one argument anyway.
    * Better to terminate file extension patterns with backslash-quote rather than dollar. It means you don’t accidentally match files that (perversely) include the newline character in their names.

    Useful function though, thanks for sharing it.

  4. Ron says:

    Ive just refactored my .emacs file using your two functions above (hoping you dont mind), the only problem ive hit so far is with downloaded .el files, such as browse-kill-ring.el. Im trying in my customizations folder to call things by the same name (as the source file) which leads to a recursive load, but its a non-issue for intergrated things like ido.el. my tempory solution has been to rename the files in custimizations to allow them to load, just wondering if you have a better solution.

    Thanks Ive been quite likeing your emacs posts recently

  5. My emacs configuration file refactor…

    In a previous post I described that a few months ago, I moved the third party elisp code under version control to make it easier to move it between machines and ensure a consistent configuration across them. The one remaining problem to solve was putti…

Leave a Reply