Wednesday, December 26, 2012

An emacs configuration smell

Have you ever seen code that just looked slightly wrong?  Like a function that takes in an argument that doesn't seem relevant to the task at hand, or a class with an overly generic name like "Utilities"?  That's what some people call "code smell".  Something doesn't seem right, and you don't know exactly what it is.  All you know is that something is rotten.

There's a "code smell" I've found in my own emacs customization code.  It's anywhere where there are several functions all related to the same thing.  Whenever this happens, I realize that an emacs package is trying to be born.  Whatever I'm doing is more than trivial, and usually it is of some use to someone else. It's worthwhile to see if someone has already tried to solve this problem, or if no one has, to try and solve it in a proper way yourself.  The proper way would be to make an actual project of it, put it on github, and get it included in MELPA or some other ELPA.

For example, a few years ago, I noticed a cool vi command as I watched a colleague work.  It cleared out everything between quotes, or parenthesis, or any kind of delimiter.  I did some looking around at the time, but didn't see anything out that was relevant.  So I implemented it myself in my initialization file.  It was about 30 or so lines of code, nothing too gigantic.  But since then the great package expand-region (available in MELPA) came out, and it basically can easily do everything I was doing.  So I got to delete all that code, and replace it with:

(defun ash-clear ()
  (interactive)
  (require 'expand-region)
  (er/expand-region 1)
  (kill-region (region-beginning) (region-end))
  (er/expand-region 0))

This is much simpler, clearer, and frankly it works much better than the half-assed thing I put together.  But if this package hadn't existed, it probably would be worth my while to create it. In the process of doing so, I'd inevitably make it much better, as well as making it public so that other people can take it and possibly even contribute.

So I advise everyone to look through their personal initialization files.  Are there packages in there that need to come out?  Are they code that can be simplified by using someone else's package? If something in your emacs initialization is worth spending more than a few lines of code doing, it's worth doing right, and for everyone.

Saturday, December 22, 2012

Encrypted emacs customizations

Sometimes you want to store passwords in your configuration. Several things need it, such as gnus and emacs-jabber. You don't want to have to lock down your whole initialization file, you just want to protect the settings you care about.

There is a way to do this, and it isn't too hard, at least on GNU/Linux.

What you need to do is to put your settings in a file in the ~/.emacs.d/ directory (assuming that you have this in your load path), with a .el.gpg suffix. The gpg suffix will tell emacs that this is something that needs to be encrypted with the gpg program (the program referenced in variable epg-gpg-program, defaulting to "gpg"). Whenever you save such a buffer, you need to supply a password with which to encode the file. It's kind of a pain in the ass, actually, but hopefully your settings are a write-once sort of thing.

Assuming that you can create such a file because you have gpg installed, you then need to make sure that those elisp files with gpg suffixes are loadable via require and load statements:

(add-to-list 'load-suffixes ".el.gpg")

Then it's a simple matter of requiring your file. If your file was named secure-config.el.gpg, then (require 'secure-config) will load it. Be warned: when it loads, you have to enter the password it was saved it so it can be decrypted. That means that you shouldn't just have the require statement in your initialization, otherwise you'd have to enter the password on loading emacs. Better to do something like:

(defun ash-jabber ()
  (interactive)
  (require 'secure-config)
  (jabber-connect-all))  

This makes sure that I'll be prompted for the password only when I want to use the program that requires the password. You could also instead "advise" the loading function (in this case, jabber-connect-all) if you want to avoid having an extra function.

I'd highly encourage you to use this system when dealing with passwords in your initialization files.

Monday, December 17, 2012

Sane font setup with dynamic-fonts

If you share your emacs initialization amongst several computers, and each has their own fonts, then things aren't so straightforward. You have two basic choices. The simplest is to not configure fonts at all, and just set up some appropriate fonts in your custom.el file that is local to your computer. The other is to engage in a complicated guessing game, matching the system type with likely fonts, or perhaps by checking for fonts and then setting.

Fortunately for us, there's a better way! (Cue emacs informercial intro music). dynamic-fonts is a package from the Roland Walker available on an ELPA that fixes this for you.
Using it, you don't have to do much of anything except:



(require 'dynamic-fonts)

(dynamic-fonts-setup)

Update: This is what is in the documentation, but the documentation is not always correct.  This will not work with emacs started in daemon mode.  A better way is:

(require 'dynamic-fonts)
;; If we started with a frame, just setup the fonts, otherwise wait until
;; we make a frame.
(if initial-window-system
    (dynamic-fonts-setup)
  (add-to-list 'after-make-frame-functions
               (lambda (frame) (dynamic-fonts-setup))))

But even this doesn't seem to work on the Mac.  I don't know why yet.

This sets up both a preferred proportional and monospace font. You should probably set it to the fonts you like in order of preference, although there are reasonable lists already pre-populated.  I'd recommend setting these font preferences in your machine-agnostic customization file ( ~/.emacs.d/init.el for me).



(setq dynamic-fonts-preferred-proportional-fonts
      '("Source Sans Pro" "DejaVu Sans" "Helvetica"))

(setq dynamic-fonts-preferred-monospace-fonts
      '("Source Code Pro" "Inconsolata" "Monaco" "Consolas" "Menlo"
        "DejaVu Sans Mono" "Droid Sans Mono Pro" "Droid Sans Mono"))

This should come before the dynamic-fonts-setup call. These fonts are listed in order of preference. They should contain enough fonts that all systems will have at least one of them.  I don't know whether my list has that property, but I suppose if I ever end up with bad fonts, I can fix the issue in either my computer or my font list.

This package is such a good idea. One of the things I'd like to do with my emacs customization is to similarly extract any good ideas into packages which I put on github. This would force me to write much better solutions than I would have written otherwise, or else remove those solutions entirely in favor of another package.

Wednesday, December 12, 2012

Customization with keybindings

Much has already been written about keybindings. I'd like to demonstrate creating two new function to do something, and binding one to a global key, and one to a mode-specific key.

I've been wanting to create a function for a while that easily lets me store and paste links to an org-mode file. Org already supports this, so this should be quite easy.

I'd like to bind a key to store a link to the present point. The function org-store-link does this, so all we need is a keybinding for this, since one doesn't exist by default. We do this with the function global-set-key. But we have to choose a key sequence first. If you want a great guide on keybinding, the awesome blog Mastering Emacs has a wonderful writeup. So, as the Mastering Emacs blog notes, all keys starting with C-c and function keys to F5 onward are available for user binding. For some reason I don't understand, org-mode takes many of these bindings for itself. So, we should check what's already bround, so I need to take a look at all currently keybindings C-h b. Looking at my keybindings, I see I don't have any bindings for C-c g, so let's use that. I'll add the following in my init.el:

(define-key global-map (kbd "C-c g") 'org-store-link)

The next part is to write a small function to add the link in an org file. There's a function already org-insert-link that has our basic functionality, but by default it prompts the user twice, which I think is unnecessary. Fortunately, the method takes a LINK-LOCATION and DEFAULT-DESCRIPTION as optional arguments, so we shouldn't have to do much work. Here's what the method looks like:

(defun ash/org-link-description (link)
  "Makes a useful description from a link."
  (cond ((string-match "^file:" link)
         (file-name-nondirectory link))
        (t nil)))

(defun ash/org-paste-link ()
  "Paste all stored links without prompting."
  (interactive)
  (unwind-protect
      (flet ((read-string (prompt &optional initial-input history default-value
                                  inherit-input-method)
                          initial-input))
          (dolist (link (delete-duplicates org-stored-links :test 'equal))
            (org-insert-link nil (car link) (ash/org-link-description (car link)))))
    (setq org-stored-links nil)))

(define-key org-mode-map (kbd "C-c p") 'ash/org-paste-link)

The definition of ash/org-paste-link has a few interesting features, but what I really want to talk about is keybindings, so I won't explain why I had to do things the way I did. I may get into writing new commands in a later post.

The interesting part for keybindings here is that I bound it to org-mode-map. That means this binding will only be in effect in org-mode buffers. I found that org-mode-map is the one to use by just running M-x apropos on the regex org.*map. In general, any mode will have a map, and the pattern is usually -mode-map, where can be whatever mode you interested in adding to.

I'll add this code to my large eval-after-load form for org-mode, so that it will only evaluated once I start using org-mode. This might be a bad idea if I want to grab a link before I visit an org-mode file for the first time, since my keybinding will not be loaded at that point. I'll have to see if that is something I'm liable to do, and if so, I'll move that keybinding out.

The lessons here are:
  1. Use keybindings for common tasks.
  2. Use global keybindings for things you might want to do in any buffer.
  3. For things you only want to do depending on the mode, use the mode specific keybinding, which can be found at the package map with suffix -mode-map.
  4. Use the user-space keybindings, those starting with C-c, and the function keys F5 on up.

Monday, December 10, 2012

Hooks, local variables, and namespaces

Sometimes you want to customize variables depending on what mode you are in. The usual way to do this is through hooks. These are variables that hold a list of functions to call when they are triggered. Most modes have a hook for when they are enabled, which lets you then use the hook to customize based on modes. For example, here's how I currently customize c++ and Java modes:

(add-hook 'c++-mode-hook (lambda ()
                           (setq fill-column 80)
                           (fci-mode 1)
                           (electric-pair-mode)
                           ;; compatible with fci-mode
                           (setq whitespace-style '(face trailing))))
(add-hook 'java-mode-hook (lambda ()
                            (setq fill-column 80)
                            (fci-mode 1)
                            (electric-pair-mode)))

This means that when I load or create a c++ file, we'll set the fill-column to 80, enable fci-mode (which has a marker which indicates when you are over the fill-column), enables electric-pair-mode (which inserts closing parens or similar item when you type the open parens), and sets the whitespace-style so that trailing whitespace is visible.

To use hooks properly, you have to understand and global and local variables.  In elisp, all variables are global. But there are different kinds of global variables. One is the truly global variable. If you set it in one buffer, it is set for all buffers. Some variables are local, so they are the same in all buffers except the one in which make-variable-local was called. Finally, there's a variable that is always local to a buffer whenever it is a setup with make-variable-buffer-local. There's also a similar make-variable-frame-local. To set a variable in a hook, you are setting it in the context of a buffer. You want to ensure when you set it, it is set just in that buffer. So it needs to be either buffer-local, or you need to make it local. The easiest way to check to see if a variable is local or buffer-local is to look at it's help page C-h f. If the variable is local, it will be noted there. You can programmatically do this with local-variable-if-set-p, which will return a true value if the variable will be local when set. The similarly local-variable-p returns true if the variable has been set and is now local.

fill-column is a variable that will become local whenever it is set, as the documentation mentions. So this is safe to set. However whitespace-style does not have documentation that mentions this. And if we check manually in ielm, we can confirm this:

ELISP> (local-variable-if-set-p 'fill-column)
t
ELISP> (local-variable-if-set-p 'whitespace-style)
nil

This looks like a bug in my customization code, then. Whenever I'm loading a c++ file, I'm changing the global value of whitespace-style! We can fix this by making the variable buffer local before we set it.

(add-hook 'c++-mode-hook (lambda ()
                           (setq fill-column 80)
                           (fci-mode 1)
                           (electric-pair-mode)
                           ;; compatible with fci-mode
                           (set (make-local-variable 'whitespace-style)
                                '(face trailing))))  

This uses the fact that the function make-local-variable returns the unquoted function, and therefore it can be used with set.

We can improve this further. If you look at the C++ and Java versions, you can see that there is considerable overlap. It's useful to make everything a function, so that if there's any issue, we can simply redefine it to change the behavior. Otherwise, if you just used a lambda, and there's an issue with it, you'd have to remove the hook manually and re-add it after fixing.

Here's our factored code:

(defun ash/c-like-initialization ()
  (setq fill-column 80)
  (fci-mode)
  (electric-pair-mode))

(defun ash/show-trailing-whitespace ()
  (set (make-local-variable 'whitespace-style)
                                '(face trailing)))

(add-hook 'c++-mode-hook 'ash/c-like-initialization)
(add-hook 'c++-mode-hook 'ash/show-trailing-whitespace)
(add-hook 'java-mode-hook 'ash/c-like-initialization)

This is much cleaner, and now it's much easier to add new behaviors to either C++ or Java mode.

You may notice the code above has functions that start with ash/, such as ash/show-trailing-whitespace. Elisp allows all sorts of characters in identifiers, including slashes. It's wise to use a personal prefix in your elisp, so that nothing you do conflicts with built-in functions or packages you may have loaded. I used to use the prefix with a dash, but I've recently seen many uses of the slash, and agree it's better. The slash makes the namespacing clear.

With the refactorings in mind, here are the key ideas to remember when working with your own configuration file:
  1. When setting variables in a hook, make sure each variable is a local variable. If not, make it a local variable in the code you are adding to the hook.
  2. Prefer functions to lambdas in hooks.
  3. Use a namespace, separated with a slash, for your named functions and variables.

Sunday, December 09, 2012

Customizing exec-path and load-path

Emacs has two main list of paths it uses to find files, the load-path and the exec-path. The load-path is a list of directories that should be used to look for load files. The exec-path is a list of directories that should be used to look for binary executables, the equivalent of the shell variable $PATH (and is initialized from it).

The exec-path is the one that usually doesn't require any modification. If it is modified, it makes sense to do so by customizing the variable, which puts it in custom.el, which I've already recommended be local-only, and not checked into git.

The load-path controls what directories are searched for load, load-library, and require. The directories in load-path are used in order of their appearance in that variable. So if there's two entries in load-path, ("~/foo" "~/bar"), and they both have a file baz.el, a (require 'baz) will load the one in ~/foo. Most people add to the load-path with the elisp add-to-list command, which will put the new entry in the front of the list, which will mean anything in that directory will override everything else. This is useful for using a more recent version of a library that comes bundled with emacs.

By default, the load-path contains with the list of emacs directories that is part of the emacs standard set of elisp, such as (on my mac) "/Applications/Emacs.app/Contents/Resources/lisp/cedet", and many other similar directories. This variable used to frequently need customization, and I've long had something in my initialization that adds everything under ~/.emacs.d to my load-path:

;; We don't really want to specify every single directory...
(let ((default-directory "~/.emacs.d"))
  (add-to-list 'load-path default-directory)
  (normal-top-level-add-subdirs-to-load-path))

This is the only way I've found to recursive add things to the load-path. When I added this, I felt it was necessary to avoid having to specify directories for every package I downloaded. Some packages, like org, needed two directories to be put in the load-path. It was annoying. But this is a heavy-handed solution to the problem. It adds a whopping 110 entries to my load-path. That can't be good.

Furthermore, ELPA already handles adding things to the load-path. I'm going to get rid of it under the theory that ELPA is handling everything I currently care about, and anything else can be dealt with as a special case. However, there is one directory I'd like to be on my load-path that isn't right now, and that's the ~/.emacs.d/ directory itself. I'd like to be able to add other .elisp files in this directory as well. The following elisp accomplishes that:

(add-to-list 'load-path "~/.emacs.d/")  

Today's lesson is a simple one: Using ELPA largely obviates the need for adding directories to load-path. But if you do have special directories you'd like to add, then use add-to-list to add them.

Saturday, December 08, 2012

ELPA and el-get

In my last post, I discussed how to tie ELPA into your customization. There's another alternative, el-get, which is a wrapper around ELPA and many other things, and lets you install and keep up to date with just about any piece of elisp out there.

The advantage here is that not everything is on ELPA. Many bits are in github, or Emacswiki, or some other more random system. Using el-get lets you easily deal with all of those things in a similar manner. The configuration options seem well-done too, though. It's a really nice system.

I played around with el-get, and I didn't have any issues. However, I wouldn't recommend it. I think more things are moving to ELPA, and anything that isn't there is best ignored for now. When Emacs 24 is the baseline emacs people use, which should be a few years from now, I'd expect every notable package to be on ELPA. So I'd keep it simple, and ignore el-get for now.