Customizing Vi

Okay, I'm not done talking about Vi yet. Lots of you out there are Emacs fans, and that's fine. I used to be too. And there are still some things I haven't figured out how to do quite as easily with Vi, such as SGML editing, but that's okay. You can either suffer through another Vi article or wait until next time for something more to your liking!

Requirements. Before you can do interesting things with Vi, you need to know how to use some mechanisms that are beyond the basics:

1.
Text buffers. There are 36 (26 alpha and 10 numeric) text buffers you can store text in. Not all of these need store only text from your documents. You can use the 26 alpha spaces to store memorized commands you can execute as needed.

2.
Text markers. Vi contains many built-in tools for editing line by line, but often you need to mark sections of text for editing that don't fall into line-by-line formats. Text markers let you deal with them.

3.
The escape filter. The shell escape is extremely powerful: it lets you filter text of your choice through one or more of the myriad text tools available to UNIX.

4.
Text abbreviation, and mapping (``abb'', ``map!'' and ``map''). These are the heart of defining your own environments similar to Emacs modes.

5.
Text buffer execution. Storing command sets into buffers instead of just text segments, then executing them with ``@-buffername''.

6.
Mode bouncing. Since stored commands must be launched from within the the appropriate Vi mode (ie, insert, command, or ex), the macro those commands are stored in must be capable of changing modes intelligently.

7.
Chained macros. One macro can call a second macro that calls a third macro, which resets all keybindings, etc, to their original state after the text has been altered according to the macros that were launched.

8.
Recursive macros. The process of ending a macro by calling itself. It's dangerous and prone to endless loops, but you can use it practially in command mode, though mostly never in insert mode.

9.
Overcoming roadblocks. Some implementations of Vi have restrictions on buffer size and putting/yanking to named buffers. There are ways of getting around these limitations in practice, and you must be comfortable in doing so.

Example Mode. Nothing teaches like experience. So let's put ourselves to the task of creating a ``mini mode'' for creating HTML documents using the above concepts.

First, we need some everyday insert mappings. These we can put into our .exrc file in our home directory. (Note, when you see a backslash (``\'') at the end of a line, it indicates an artificial line break that would not exist in your macro, but is set here for typographical reasons.)


ab Hndoc <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">^M \
<HTML>^M<HEAD>^M<TITLE> </TITLE>^M^M^M</HEAD>^M \
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">^M^M<BR>^M^M \
</BODY></HTML>^M

This first abbreviation means that when you type ``Hndoc'' into a document, those letters will immediately be expanded into the basic tags for an HTML document. Some keystrokes, such as the return key and the escape key, cannot be entered directly into an abbreviation or macro. They must be ``escaped,'' meaning that another character must precede them so Vi doesn't prematurely interpret the character. When you see ^M, you are seeing an escaped return carriage character, for example.

So, all of what you see above will actually be on the same line when you type it into your ~/.exrc, and the returns are entered by pressing Ctrl-v. You hold down the Control key and tap the ``v'' key, then enter either the return key or the escape key. Then the proper sequence will be inserted into your saved keystroke sequence. In the future, I'll refer to these strokes you type as ``CtrlVEsc'' and ``CtrlVRet'' instead of by the symbols that appear on the display when you type them.

You saved yourself quite a few keystrokes with this single abbreviation already. But there's much more.

How about ab H-1 <H1></H1>CtrlVEsc4hi This will abbreviate the sequence ``H-1'' and create a level 1 head with it, leaving the cursor between the begin and end tags in insert mode. (CtrlVEsc4hi tells you to hold Ctrl-v and hit Esc, thus bouncing to edit mode, moving the cursor four places to the left, then turning insert mode back on.)

You can create a host of these type of commands. But what about something more interactive?

Try this:

ab Han <a href="CtrlVEsc:r!cat \
/dev/ttyCtrlVRetkJx$a"></a>CtrlVEsc?</a>CtrlVReti 

This will bind the ``Han'' sequence (``H'' for HTML mode, ``an'' for anchor) to an anchor element, but before it completes, it will ask you to enter the URI to reference. When you enter Crl-D to end your URI input, the rest of the macro will complete and finish your entry, leaving you in insert mode with your cursor positioned to enter the text between the start and end tags. The last part of the macro joins the two lines created, moves to the end of the line, then searches backward for the start of the endtag, then bounces back into insert mode for you.

Let's say you are editing your document and decide you want to highlight some text and insert an anchor element around it. You could go with the following map command:

map ^X^a `oi<A "href="#">CtrlVEsc`ca</A>?">CtrlVReti

This macro assumes you mark the first part of the anchored text with marker ``o'' (for open tag) and the last part of the anchored text with ``c'' (for close tag). It inserts open anchor tag before the text, bounces to edit mode, moves to the close tag marker, bounces back to insert mode, inserts the close tag, bounces to edit mode, searches backwards for the href value, then bounces back to insert mode so you can insert your text at the appropriate location.

Further, you could combine some macros by chaining them together. Let's say you have a macro ^Xg for ``get text'' that said:

map ^Xg :r!cat /dev/ttyCtrlVRetkJx

which effectively asks you for input, then pastes that input into your document at the current cursor location. You can embed this macro into another macro, thus chaining them together:

map ^Xu 0i<a href="#EscVEsc^Xgi</a>EscVEsc

This macro inserts the opening anchor text, stops, starts the ^Xg macro to get the text for the URI reference, then completes the insertion of the closing anchor tag.

You could also put each of these macros in a file other than .exrc, such as ~/vimstuff/html.exrc. Then, when you wanted to use an HTML mode, you could simply type :so ~/vimstuff/html.exrc while in Vi mode.

This should give you a few ideas on how to build an HTML ``mode'' for Vi. Mind you, you can easily start with modes developed by others and expand or replace from there. I use Vim (see http://www.vim.org), and it comes with a HTML syntax highlighting mode, but there is still a lot of room for customization of abbreviations, macros, mappings, and for sourcing external macro files and storing them into memory.



dsj@dsj.net