dcsimg

Vimming to New Heights

A major release of the Vim text editor packs a whole lot of new features.

Everyone knows that there are three things you’re not supposed to discuss in polite company: politics, religion, and text editor preference. However, rules are made to be broken, and the recent release of Vim version 7 prompts just such an occassion. While George W. Bush, John Kerry, and Jesus may be keeping mum, the rest of us can celebrate a significant upgrade to a popular editor.

The complete list of new features in Vim 7 (http://www.vim.org/) is substantial. Major enhancements include native spell checking, smarter completion for a bevy of programming languages, and remote and compressed file browsing. In fact, the features are so numerous that even a simple list wouldn’t fit in the span of these few magazine pages. (See the sidebar “A Sample of Vim Goodies” for a brief list of notable additions.)

If you’d like to review the comprehensive list of changes, install Vim 7 and type :help version7. Or, if you’d like to check out the new features before committing to an upgrade, visit the Vim Documentation project at http://vimdoc.sourceforge.net/. Here, let’s look at some of the most useful new features of Vim 7.

Spell Checking

Ironically, Vim has sorely missed good, native spell checking. Sure, there was support for spell checking via external tools, but such linkages were slow and never felt well-integrated. With Vim 7, though, spell checking has been implemented as a first-class feature. Indeed, if you’re using the graphical user interface version of Vim 7, you can even enable those familiar red squiggly lines to highlight words with dubious spellings.

To turn spelling on in Vim, set the spell option with the command :set spell. Or if you just want to spell check the current buffer, type :setlocal spell. You can also specify the language to use by setting the spelllang variable when you enable spelling. For example, to set the language to the U.S. version of English, you’d type :set spell spelllang=en_us. For British English, replace en_us with en_gb.

Once spell checking is turned on, you can use [s and ]s to move to the first flagged word before or after the current cursor location, respectively. A flagged word is not necessarily a misspelled word. Vim flags misspellings, but also flags certain words that are rarely used and are likely to be a misspelling of a more common word. Vim also flags not commonly used within a specific region (such as British spellings in the context of United States English), and flags words that should be capitalized. If you’d like to only jump to words that are plain old misspellings, you can use [S and ]S instead.

When the cursor moves to a misspelled word, you can review a list of possible spellings by pressing z=. When the long list of alternates pops up, type the number to choose the proper spelling. If you want to repeat the replacement for all similarly misspelled words in the current document, type :spellr.

Often, you’ll come across words that the spell checker fails to recognize, but are in fact correct. (Proper nouns, recent additions to vernacular, and foreign words are but a few examples.) Most of the time, you want to add those to the dictionary to expand the vocabulary of the spell checker. If you’re on a “questionable” word, press zg to add the word to Vim’s list. If you accidentally “whitelist” a misspelling, use zw to remove the word under your cursor from the list.

Tab Pages

Most modern text editors and integrated development environments — such as Eclipse and gEdit — allow you to open multiple documents in the same window. To switch between documents, you simply click on a helpful tab at the top or bottom of the window. Vim now supports the same feaure, but goes one step further. Not only can you open a new document in a separate tab, but you can create a separate “tab page” that allows you to have separate, multiple buffers in split windows within each tab.

Opening new tab pages is as easy as opening a new buffer. Type :tabe filename to open a new tab right after the one you’re currently editing. Or, if you want to open a file in your path, but not necessarily in the current directory, use :tabf instead.

You can move around tab pages by using the commands :tabn and :tabp to go to the next and previous tabs, respectively. You can also use :tabr to go to the first tab in the list and :tabl to go to the last.

One of the handiest features of tab pages is that if you have multiple tab pages opened, you can run a single command and apply it every open tab. When in any tab, run :tabd with the command you’d like execute to process each tab in left-to-right order, starting with the left-most tab. For instance, if you have several source files open and you’d like to change the name of the global variable foo to bar, run run :tabd%s/foo/my_bar/g.

Undo Branches

A guy walks into a bar and starts typing away at some code. After a while, he realizes that he needs to see the state of the file a dozen or so changes back. So, he hits undo a bunch of times to roll back state. Unfortunately, before he can “redo” his typing, he accidentally performs a paste action and loses all of those changes. Does this sound familiar? Unfortunately, it’s probably all too common of a story.

Fortunately, this won’t happen anymore in Vim 7. Instead, every time you perform an action at a position other than the top of the undo stack, Vim branches the undo list, allowing you to switch between the old undo branch and the new one. Confused? Take a look at Figure One.

Let’s say you open a new file and make five changes (C1 through C5). Then you decide to undo things all the way back to C2 (indicated by the red, dashed lines) to try a different approach. At that point (C2, again), you make changes six and seven (the blue line indicates a new edit). But that course fails to pan out, and you want to return to the state of the document after C4, where you make one additional change, C8.

Figure One: A tree of Vim 7 undo branches

A tree of Vim 7 unfo branches

With undo branches, you can use g– a couple of times to undo back to the original change branch and then move back to C4 to continue from there with your eighth change, which starts yet another, third branch. Powerful, no? Simple, too.

However, the user interface for undo branches is far from simple or intuitive. As it turns out, there’s no way to get a neat little graph of your changes, like the one shown in Figure One. Instead, you can only view the undo branches by running :undolist, which would produce something like this if you run it after C8:

 number changes time
 5       5 56 seconds ago
 7       4 45 seconds ago
 8       5 6 seconds ago

The first column shows the absolute position of that branch’s newest revision in the flat undo stack. The second column shows how many total changes are in that undo branch, from the beginning of the undo stack through the newest revision in the branch. Finally, the third column shows when that branch was last edited.

To move around the branches of the undo list, you use g+ and g-. These commands cycle forward or backward one element in the flat undo stack. So for example, if you’re at C8 and hit g- you return to C7. From there undo and redo move you up and down the second branch. Similarly, if you hit g- two more times (or hit 2g-) you cycle back to C5, which would put you on the original undo branch.

Hopefully, a visual map of recent changes can be added in the next update.

New Highlighting Features

Vim adds a couple of handy new higlighting options that won’t change your life, but will make life a little bit easier.

First, matching parenthese are automatically highlighted. This feature is present in a lot of other text editors, but up until now, you could only match parenthesis in Vim using % to jump to the parenthesis that matched the one under your cursor. Now, with highlighting enabled, you won’t have to hit % much anymore, because when your cursor is over a parenthesis the matching one is automatically highlighted. Of course, that only works if the matching parenthesis is currently on screen (and less than 100 lines away), so % won’t go away completely.

Another useful highlight — especially if you tend to edit on a high-resolution screen using a tiny font — is the “crosshairs”. When cursorcolumn and cursorline are set, Vim highlights the entire line and column that contain the cursor. The very clear “+ ” marks the spot.

As handy as the “crosshairs” are, it’s downright annoying to have the line and column highlight while you type. It’s also not very handy to repeatedly type :set cursorline cursorcolumn every time you need to find the cursor. Instead, set Control-C to toggle the highlighting on and off by putting :map Control-C cursorline!cursorcolumn! in your ~/.vimrc file.

Location Lists

A Vim quicklist is a navigable list of file locations that you get from parsing an error file after running :make or :grep. In Vim 7, a location list is a per-window quicklist.

Let’s look at a scenario: Let’s say that you’re working on an application and a library at the same time. The application is in one Vim window; the library is in another. If you use :lmake to build your application, the error list for the application does not clobber the error list of the library. Similarly, you can use :lgrep to search header files for reference information, without interfering with another error list that you’ve only worked through partially.

The commands for managing a location list are almost identical to the commands for dealing with a quickfix list, except the c is replaced by an l (lowercase “L”). For example, to move to the next item in a location list, type :ln instead of :cn; to list all items, use :ll.

You can also save a location list (or quickfix list) by opening it up in a window (with :cw or :lw) and saving it just as you would any other file. Then, you can load it later into a location list with :lfile filename. You can use this feature to save the results of a search that you want to reference later.

Internal Grep Support

Speaking of searches, Vim now has internal support for “grep”. In previous versions of Vim, all searches were conducted with an external grep program (and if you happened to be on a system without an external grep program, you were out of luck). In Vim version 7, you can run the external grep feature in exactly the same way, but there’s also a new :vimgrep command that performs a search using built-in code.

The internal grep functionality is not universally better than the external grep command. For instance, the internal grep can be a lot slower than the external grep, because it loads whole files into memory to search them. For that reason, you’ll probably find yourself using both the old :grep command and the new :vimgrep, depending on the task at hand.

:vimgrep searches use the standard Vim search patterns, just like when you search with the :s// command. (The overall syntax is almost identical.) For example, to grep for myfunc() in all of your C files, you’d run :vimgrep/myfunc()/g*.c. The results are placed in a quicklist, just like :grep.

One of the big advantages of the internal grep functionality is that it uses Vim search patterns, meaning you don’t have to use different search expressions for intrafile searches versus interfile searches. Also, since the grep is running within Vim it can take advantage of knowledge that Vim has about the encoding of the documents being searched, including different types of newline characters. Finally, :vimgrep can search zipped files or files located on a remote server, something that is impossible from within Vim using the external grep.

Omni Completion

One of the big advantages that full-fledged IDEs have had over Vim is an ability to use code context to provide you with likely completions. Vim has had completions for a long time (accessible as Control-X-Control-N or Control-X-Control-P), but they weren’t context-sensitive. Instead, you received a list of possile matches derived from open and linked files and the partial word you’ve typed.

Finally though, that’s starting to change. Vim 7 offers “OmniCompletion.”

Press Control-X-Control-O to run OmniCompletion. It reads the text of the word leading up to the current position of the cursor and attempts to deduce (based on file type and context) what you might want to complete. For example, when editing an HTML file, if you’ve just opened a head tag and type < followed by Control-X-Control-O, you can cycle through the tags that are appropriate for inside of a document head. Similarly, if you “omni-complete” the name of a struct variable in a C file, you’ll cycle through the list of members for that struct.

OmniCompletion works by calling the function (omnifunc) with the text to complete. Vim uses the filetype plug-in to load a “complete” file based on the type of file that you’re editing. The file provides an omnifunc function appropriate for the current file type. Hence, OmniCompletion can be easily expanded to support new kinds of files.

To turn completion on, make sure that the filetype plug-in is active by running :filetype plugin on.

(One caveat: some completion functions have external dependencies. For instance, if you want to complete C or PHP files, you need to run exuberant-ctags on the source files first to generate a tags file.)

Automatic completion has one more handy little feature: Instead of simply cycling through possible completions, Vim now displays a list of the possible completions in a popup menu. If this doesn’t work automatically, first check to make sure you are using a terminal display that can support at least eight colors. If you are, enable pop-up menus with :set completeopt+=menu.

When a popup menu appears, cycle through the matches as you normally would (with Control-N and Control-P), or cycle multiple options at a time with Page Up and Page Down. You can accept the highlighted option at any time by pressing Control-Y. You can dismiss the pop-up with Control-E.

Conclusion

Vim 7 doesn’t feel or look like a brand new editor, but as something so central to millions of software developers, that’s probably a good thing. Keeping Vim familiar while expanding its capabilities allows you to adapt to and adopt new features at your own pace, according to your own needs.

At the same time, the list of new features is filled with lots of great little additions that clean up many of those annoyances that made Vim less than perfect. Of course, it’s still not “perfect,” and the Vim vs. Emacs battle won’t be won with this release, but would you really want that? After all, arguing about text editors is much more fun than arguing about religion or politics.

William Nagel is Chief Software Engineer for his company, Stage Logic, as well as a freelance writer and software consultant. He can be reached at bill@williamnagel.net.

Comments are closed.