Editing tab-separated files with Emacs (Shallow Thoughts)

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Mon, 16 Jul 2012

Editing tab-separated files with Emacs

I wanted to keep maintenance records for my car in a local file. Things like the date and mileage of the last oil change, when the timing belt was replaced, stuff like that.

I didn't want to hassle with databases or spreadsheets -- a simple, human-readable file is a lot easier to deal with. But I also wanted it in a predictable format so it could potentially be parsed later: I might some day want to write a program that keeps track and reminds me when I need to do things. (You'd think this program would already exist, but curiously, I haven't found one.)

So, something like:

7/9/12 <TAB> 86306 <TAB> Oil change, filter
6/11/12<TAB> 84813 <TAB> Smog test

Simple, right? And super easy just to type in in a text editor.

Well ... in emacs, maybe not. As an editor oriented toward programmers, emacs tends to prefer spaces instead of tabs ... and that's normally the way I prefer it. Tabs are a bad idea in most software projects, unless everybody on the project has already agreed on a tab style and width. (The complete tabs-vs.spaces religious war is beyond the scope of this article, but take my word for it that they can be a problem.)

But this wasn't code, and I needed an easy way to get those tabs into the file. Of course, I could quote them directly: type Ctrl-Q TAB every time I wanted a tab. But I knew I wouldn't remember to do that every time.

So I needed a local variables line, sometimes called a modeline, to flag this file as different from any other file I edit -- in this one, I really do want a TAB when I hit the TAB key.

My first try put this as the first line of the file:

-*- Mode: Text; indent-tabs-mode: t -*-
(Actually, my first try omitted the -*- part and didn't work at all, but let's ignore that part.)

When I re-loaded the file, emacs loaded it in text mode, and indent-tabs-mode was set to t if I checked it with describe-variable. Great! I could add new lines at the end of the file, and when I hit TAB, emacs inserted tabs. But wait -- if I added a line at the beginning of the file, and typed something lke 7/9/12<TAB> ... it inserted a space, not a tab.

It turns out indent-tabs-mode isn't really documented. If you check the help, it says:

Indentation can insert tabs if this is non-nil
-- note that "can" insert, not "will" insert, a tab. So how could I get emacs to really insert a tab, every time I hit the tab key?

Well, of course, I could bind the TAB key to "self-insert". But I didn't want to change it for every file, only for this one. how could I make that happen as part of a local variables line? The local variables line documentation shows how to set variables or file modes, but it looks like you can't bind keys or run functions.

Well, you can't run functions, but you can define a new mode that runs functions. At the suggestion of some helpful people on the #emacs IRC channel, I defined a new mode in my .emacs, like this:

(define-derived-mode tabbed-mode text-mode "Tab separated mode"
  (local-set-key (kbd "TAB") 'self-insert-command)

Then in the file, I put this line:

-*- Mode: Tabbed -*-

Now, every time I load the file, emacs turns on tabbed mode -- which is just text mode except that the TAB key always inserts a tab.

Tags: ,
[ 19:35 Jul 16, 2012    More linux/editors | permalink to this entry | comments ]
(Commenting requires Javascript from ShallowSky.com and Disqus.com, and a cookie from Disqus.com.)
blog comments powered by Disqus