A few weeks ago, I had the chance to attend a few courses on Perl and one on giving technical presentations, held by Perl guru and uber-geek Damien Conway. They were fantastic—just like the ones last year—so I should really write a post of its own about them. Strongly recommended.
But for now, this is about one particular thing he said about editing: you need to have a shortcut in your editor that cuts or copies the text between two given characters around cursor, or point in Emacs lingo. This lets you do many frequent editing tasks easily. Say you’re going through a source file and want to move {}
-delimited blocks around, or copy the field you’re on in a CSV file, or the current section in a Markdown file (from #
to the next #
, roughly).
Damian showed this off in Vim. I knew right away that I wanted it in Emacs. There are of course specialized functions for doing things with certain groups of delimiters, such as the ubiquitous sexp-based functions in Emacs, described extensively on the EmacsWiki. But these rely on pre-configured groups of delimiters, and to kill the text, you have to do one extra operation. I liked the idea of having a single function, and thus key binding, to do all of it. And most importantly, it seemed an interesting challenge for my still-developing Emacs and Lisp skills, so I didn’t even do a lot of research before I dug right in and wrote delim-kill.el.
delim-kill.el contains a single convenience function for editing structured data: delim-kill. Given two characters FROM and TO, delim-kill kills the text between the first occurrence of FROM before point and the first occurrence of TO after point. FROM and TO may be identical.
If FROM and TO are not identical, the function preserves the balance between the two characters: For each FROM that is encountered while looking for TO, one additional TO is required; and vice versa. For example, in “{ foo X{bar} baz }”, with X being point and “{” and “}” as delimiters, the text “{ foo {bar} baz }” will be killed, not “{ foo {bar}”.
I had fun writing this. It turned out to be a bit harder than I expected, mainly due to all the corner cases like point being on one of the delimiters—like most programming, really. I wrote plenty of unit tests to be sure to handle these cases. It’s very little code now, but when I first had a working version, it was twice as big. Once I had it working, I could see lots of symmetry between the different cases that I could extract into shared code.
Also, I finally learned the condition-case error handling of Emacs. And being able to pass functions as arguments is just great, coming from my mostly-Java day job.
Try it out if it sounds useful to you, and let me know what you think.
Slightly edited 2010-05-16.