vi: totally bitchin'


2:0 You can execute a shell command and capture the results in the buffer (unlike :!, which sends its output to stdout). The !! command executes a command and replaces the current line with the results. You can run a command which reads stdin and writes stdout to modify a range of lines in the buffer. To sort the lines between the current line and the end of the file, use .,$!sort and the lines will be sorted in place in the file.

2:1 One of the most nugatory of vi's commands is the @ command. If you yank vi commands into a named buffer - say buffer a - then you can execute those commands by typing @a. Science has yet to find a practical use for this command that has anything to do with editing a file. You can, however, use commands like this to make vi solve a maze...

2:2 vi lets you assign a complex series of commands to a single keystroke with the :map command. The syntax is :map shortcut commands where commands are what you are binding to shortcut. If, for some reason, you wanted an easy way to swap lines in a file, you could try something like this: :map q "add"apj to map q to those commands. Note that if you want to restore something within a macro, you've got to put it in a named buffer (hence the "a). The j at the end moves the cursor down one line in preparation for another execution. You can also use commands that leave you in insert mode: :map =a c/long pattern I don't want to type^M will map =a to a long change command. If you don't want to be left in insert mode, you can embed escapes in your commands with control-V: :map % /ex^[cwvi^[n will search for an occurrence of ex and change it to vi and then place the cursor on the next occurrence of ex -- a pretty simple search and replace. Note that to enter the escape (^[) into the macro, you need to type a control-V followed by the escape key. The same goes for entering a carriage return into a macro.

Some versions of vi let you use function keys or short escape sequences, but these aren't portable, so you'll have to figure out what your system allows, and just stick with that.

2:3 The :abbrev command lets you map a key sequence to characters which get expanded while in input mode. For instance, if you always misspell "the" as "teh," use the command :abbrev teh the and then every time you type "teh" it will automatically turn it into "the." You can make an :abbrev to turn your initials into your name or an acronym into a project name. You can also make it leave input mode (and potentially execute commands or something) by inserting an escape in the expanded string (using ^V).

2:4 Skip this section unless you want your brain to hurt. Let's say we wanted to make a search and replace command that would convert European dates (dd-mm-yy) to American dates (mm-dd-yy). You can use \(, \), and \n around a pattern that you're matching to save and and restore it in the replacement pattern. If you want to replace all occurrences of hi and Hi with ho and Ho, you would do this:

The \1 in the replacement pattern becomes the h or H from the search pattern. The date conversion search and replacement pattern mentioned above looks like this: The \2, \1, and \3 are replaced by the patterns in the second, first, and third set of \(...\)'s respectively.

Even farther down the slippery slope of esoteric regular expressions is the dreaded \{m,n\}, a feature found most often in ed and sed and never (if ever) in vi. It's interesting and pertinent enough to include here, so here it is. \{m,n\} will match between m and n occurrences of the immediately-preceeding single-character regular expression.

2:5 The ctags feature in vi was designed to let you navigate easily around code spread across several files. Once you use ctags(1) to create a tags file, you can find the definition of any function (or macro, typdedef, struct, global, etc...) by placing the cursor on the function (or whatever) whose definition you want to find and pressing ^] (control-right square bracket). ^] has the unfortunate distinction of also being the default escape sequence for telnet(1). (You can avoid this conflict by redefining telnet's escape sequence (to ^A, for example) by getting into telnet's command mode (with ^]) and then typing set escape ^A. You can also avoid this problem by just using rlogin(1).)

Some versions of vi (notably System V derivitives) don't support the ^] method of jumping around. You will have to use the :ta tag command.

Some versions of vi maintain a stack of about half a dozen "hops" around your code. You can return to your previous location by using ^] when you're not on anything that vi might interpret as a function (or whatever) or by using the :ta with no arguments. If this backward jumping isn't supported in your version of vi, you can at least get to the most recent hop by using :e# if it happened to be in another file and by '' if it happened to be in the same file.

2:6 The :set command lets you set many usefull features. Type :set all to get a list of all the options you can set. A few of the more useful features are:

:se with no arguments lists the current setting of options that have been changed from their defaults.

In order to turn off options that can be turned off, insert a no before the option (as in :se noai to turn off auto-indent and :se nomesg to disallow messages written to your tty).

2:7 If you have a bunch of :map, :alias, and :set commands that you would like to automatically invoke when you start vi, the .exrc file is the place to put them. The .exrc file in your home directory will be read whenever you start vi, but you can also have a .exrc file in a subdirectory - this .exrc file will override the one in your home directory.

To use a .exrc file, just place commands in it, one per line, that you would normally enter into vi's command mode.

2:8 vi has a couple of useful command line arguments.

2:9 If you're wondering which is the better editor between emacs and vi, always remember that emacs has a vi mode, but vi doesn't have an emacs mode.

Here endeth the lesson.

vi evangelical series /
January 1995 (updated April 9, 1999)