Recently I was assigned/volunteered for this task at work. Fairly inglorious, basically it ends up being writing a whole bunch of XML configuration. Nothing more exciting than pounding out endless tags. My editor of choice is emacs, mostly because it runs really fast, and I don't like the 'escape' command/insert metaphor of VI and clones. I should repeat that last bit: I like emacs because it is FAST. That's right, the editor who's acronym expansion used to be "Eight Megabytes And Constantly Swapping" is now one of the fastest editors. If you don't think so, try loading up a 80k line XML file in your favorite IDE.
So emacs XML mode does allow for some validation and other things, but normally it does not insert closing tags and other 'niceties' that editors such as TextMate does. So I found myself repeatedly hammering out the same XML blocks, and I thought, "I know emacs has a template system, I should use that." And indeed it does, in fact emacs as 2 separate but complementary systems. The first is 'skeletons' which provide a method of defining a mini-template. It has a pile of features including the ability to automatically put your point in an 'interesting' spot of the inserted text. So it can position your cursor at the middle of 2 tags or in an attribute or wherever. You can then bind these skeletons to key commands.
Binding to key commands is handy, but combined with the abbrevation mode you end up with a powerhouse editing shortcut. Simply put, abbreviations are small letter sequences that get expanded. Simple text substitution is trivial, turn teh to the. Or, you can call an emacs-lisp function, such as a skeleton function you just previously defined. Meaning with a few keystrokes and no special control-bindings you can pound out code when the base format (XML is so verbose!) does not allow shortcut definitions.
Of course each little skeleton (or what one might call "macros" but we don't in lisp because there are already lisp macros which are way different) is pretty custom. But they are so trivial and easy to write, even for small hour or two projects it makes sense to define them. Same with abbreviations. This has easily saved me two hours already, combined with the 45 minutes it took to learn, is about 1 hour and 15 minutes saved.
I should also mention, I am in no ways a lisp expert. Copy and pasting emacs lisp functions into ~/.emacs and doing a little bit of modifying is the extent of my expertise. It took me 10 minutes to figure out how to use the interactive special form properly. I usually use Google to find solutions to my emacs-lisp problems. But defining these skeleton/abbrevs was so stupidly trivial practically everyone should learn it.
Here is a brief example, lets say you are typing the same piece of HTML over and over, it looks like this:
<div class="boxy">
<div class="custom">
text
</div>
</div>
Lets say the div classes are always the same, but the text inside is what is unique. So you define a skeleton:
(define-skeleton
boxy-custom-div
"My Custom/Boxy div nested skeleton"
> "<div class=\"boxy\">" \n
> "<div class=\"custom\">" \n
> _ \n
-2 "</div>" \n
-2 "</div>" \n )
Basically anything in a quoted string is echoed verbatim. Escape double quotes with a \ as usual. The proceeding > means 'intend according to the mode'. The \n inserts a newline as expected. The -2 is to properly un-indent those lines by 2 spaces. The bare _ means that is an area of interest. What it means is when the skeleton is applied, the first 'area of interest' is where the cursor will be left afterwards. You can define multiple interesting areas and do more advanced things by having skeletons wrap around existing text. However that does not play well with the abbrev trick I will say next.
The magic comes in with abbrev mode. First off enable abbrev mode with M-x abbrev-mode in your buffer. Then you need to define an abbreviation, but you can't do it with the command sequence C-x a l which the manual tells you. Instead you have to execute the following lisp code:
(define-abbrev
html-mode-abbrev-table
"cdiv" "" 'boxy-custom-div)
The first string "cdiv" is the trigger text. The second string is what to substitute it with (nothing) and the last argument is what function to call after the text was inserted. The net result is with 5 keys "cdiv" then space/enter you get to expand out all that HTML. Clearly the more repetitive text you have the bigger of a win this is. Unfortunately skeletons that are triggered via abbrev-mode do not properly work to wrap existing text. That mode of skeleton is very powerful, it lets you wrap multiple (up to 16) chunks of text in a row at arbitrary boundaries in to different points of a skeleton in order. The slight annoyance is you have to mark with C-space each point of interest. I personally find that awkward.
Of course a neater approach would be to ASK in the mini buffer what you'd like to insert in. And you can do this in skeletons. But there is only so far you can go with that, since you have to ask the fields in order and you can't post-insert text. Lets say you are defining database schemas, you might as well only enter the table name and have your skeleton guess the primary key name. This is starting to get a little complex, and this is where my story changes slightly.
I ran in to this particular problem, wanting to do non-trivial calculation and manipulation in a skeleton. The docs say "maybe you should write an emacs-lisp function instead", which is a fabulous idea. I don't really know enough about lisp or emacs lisp so it seems like a good time to learn. Luckily I work with the semi-famous Steve Yegge. As you may know or have guess, Steve is a lisp... well fan. And I raised this to him, that skeletons and abbrev-mode ruled and I needed to learn more emacs-lisp. To which he said "read the book on my desk". Technically it's a print-out in a binder of a book, and the book is "On Lisp" which I am now reading.
The interesting thing about Lisp is it was invented in the early days of computer science (ie: 70s and early 80s) when people didn't "know" how to program. Thus I believe people asked questions like "what does it mean to program" and other seemingly useless philosophical type questions. The result of which is Lisp, a meta-programming language that facilitates writing and rewriting itself. Of course now, being smart programmers we invent useful languages like C++ and Java and C# which are safe and don't let you change too much about the language itself. And we are better off for it, right?
No comments:
Post a Comment