Wednesday, December 05, 2012

Fixing some incorrect initialization

Remember when I removed the setting for c-buffer-is-cc-mode? I couldn't remember why it could possibly be important to set it in init, especially since it was buffer local.  Well, after restarting, I find I cannot paste anymore, and I'm getting an error involving c-buffer-is-cc-mode. In these situations, it's best to do M-x toggle-debug-on-error.

Reproducing the problem, I see from the backtrace that my error comes from my advice I define for pasting:

(defadvice yank (after c-indent-after-yank activate)
  "Do an indent after a yank"
  (if c-buffer-is-cc-mode
      (let ((transient-mark-mode nil))
        (indent-region (region-beginning) (region-end) nil))))

The error is now easy to spot. Not every buffer has c-buffer-is-cc-mode defined, so when elisp tries to evaluate the undefined variable, it throws a void-variable error. The fix is pretty simple, which is to use boundp, which checks to see if a symbol is void or not.

(defadvice yank (after c-indent-after-yank activate)
  "Do an indent after a yank"
  (if (and (boundp 'c-buffer-is-cc-mode) c-buffer-is-cc-mode)
      (let ((transient-mark-mode nil))
        (indent-region (region-beginning) (region-end) nil))))

After evaluating this, everything works well once again. The hacky setq of c-buffer-is-cc-mode is removed, and the yank advice now stands on its own.

Let's fix one more problem before calling it a day. I use an awesome package called key-chord. This enables me to set the press of two keys simultaneously (such as "j" and "k") to a command. I noticed that when I start up, though, it doesn't work until I toggle the to disabled, and then back to enabled.

First, I noticed that (key-chord-mode 1) is called before any of the key-chord-define-global is called. Maybe it should be last? I try it out, but it doesn't help the problem. Maybe the problem is that the feature isn't actually loaded yet. I looked at my config, and saw that I only do operations on key-chord in eval-after-load calls (which I'll be writing about later). But nothing ever loads it!

When I invoke M-x key-chord-mode, what must be happening is that the autoload for key-chord kicks in, loads it, then evaluates everything in all the eval-after-load calls, one of which calls (key-chord-mode 1). Then the M-x invocation executes, which turns the mode off. To fix this, we just need to add a (require 'key-chord nil t) statement. And that does fix the problem.
I'll go into the require statement in another post, and why I use the additional arguments to the function.

I looked in my init file for other locations in which I'm making the same mistake. I see that I have setup for bc (a breadcrumb system), but no actual library backing that up right now. I checked, and it isn't available on any of my ELPA servers I use. To me, this is a bad sign. ELPA makes things so much easier that I think it's better if I use some other bookmarking solution and retrain myself. So I'm deleting my config for this, and I'll investigate other bookmarking systems later.

The lessons I've gotten from today's debugging session are this:
  1. Strange things in init files are a sign that there may be a bug. Don't patch around it. Find the problem and fix it!
  2. After modifying your init file, load it up and try a few things. Fixing things while working on your init file is much better than discovering some problem at a more inconvenient time. That's when bad fixes and hacks start to creep in.
  3. If you want a global mode to be on as soon as you start up emacs, don't forget to require the package. Most other things don't need the require, since they have elisp autoloads that will load up the code when you execute one of the package's commands.

No comments: