Introduction to the Text Editing for Programmers

Professor Norm Matloff

Dept. of Computer Science

UC Davis

matloff@cs.ucdavis.edu

Basic precepts:

Programming should be enjoyableprocess, but takes a lot of time.

To save time and frustation, make good use of a sophisticated text editor.

of a sophisticated text editor. You should use advanced editor features to help yourself , not to please your professors.

, not to please your professors. Another important way to save time is to learn good debugging techniques.

Some good editors (all free, all multi-platform):

vim, a popular advanced version of vi

emacs, a programmer classic

jEdit, newer and very interesting

don't use pico, which was designed for non-computer experts

We will use vim examples here.

But "You see one, you've seen 'em all": Other advanced editors have similar features.

If you have no exposure to vi at all, read my 5-minute introduction to vi.

at all, read my 5-minute introduction to vi. Note that vim also has a nice GUI version, gvim , allowing for mouse operations, clickable icons, etc. To get gvim , invoke vim with the -g command-line option.

also has a nice GUI version, , allowing for mouse operations, clickable icons, etc. To get , invoke with the command-line option. Our example program: Lnk.c

Topics:

Suppose we are currently at a call to Insert in Lnk.c (black cursor, 4th line of code):

We'd like to check whether we're using the function argument correctly. So, we want to move to the definition of the function.

First of all, we want to "mark our place," so we can easily move back to this line. We type

ma

This tells vim to "remember" this spot under the name a.

Now, to move to the definition of Insert(), we could simply use vim's search capability, typing /Insert. But this may just bring us to other calls to Insert(). A better way is to type

gD

The result is that the cursor does indeed move to the definition of Insert():

Now, to get back to our saved place, we type

`a

We can save places (and other items) under the names a, b, c, etc., which are called registers.

The gD command works for variables too. On the same line as before, suppose the cursor is on the variable NumY:

If we now type gD, the cursor moves to the definition of NumY:

Extremely useful --use them often!

In our example of the usage of the gD command above,, say we want to simultaneously look at both the call to, and definition of, Insert(). We could go to the definition first:

Now, let's split this into two subwindows. Type

:sp

(or in gvim click Windows then Split), with this result:

You can move the cursor around independently in each of the subwindows.

So, to see both the definition of and call to Insert(), let's have the lower subwindow go to the call to Insert():

Move to the lower subwindow by typing ctrl-w ctrl-w (or, in gvim , by clicking the mouse in the other subwindow).

(or, in , by clicking the mouse in the other subwindow). Type /Insert to go to the call.

Result:

This way we can easily check whether we have specified a function's parameters properly, etc. There are many other settings in which having two subwindows will help clarify our work.

The ctrl-w ctrl-w operation toggles, i.e. hitting it a second time will return you to the first subwindow (or will make you cycle through subwindows, if you have more than 2).

If I want to go back to using just one window, we type :q in the subwindow to be deleted.

Oops! We all make mistakes, but sophisticated editors allow you to undo them---in fact, undo the last N changes you made. A good editor also allows re-do, which means that if you undo something but then decide you want it after all, you can retrieve it.

In vim, type u for undo, ctrl-r for re-do.

Often one wants to delete an entire set of lines or other region. Though one could do this character-by-character or line-by-line, it is faster and less distracting to apply a single delete operation to an entire region..

Moreover, by using a delete operation on an entire region, this sets up ways to copy or move the region.

Suppose for instance that we wish to move the function PrintResults() to a position just before the function Insert(). In vim we could first enter visual mode.

In gvim, one simply creates the block by dragging the mouse from the first to the last character of the region, upon which the region becomes highlighted.

In vim, we move the cursor to the first character of the region, then hit v, then move the cursor to the last character of the region. For our example here:

Move the cursor to the beginning of PrintResults().

Hit v .

. Move the cursor to the end of the function.

This will define a region, which will now be highlighted:

Now hit d to delete the region. Note that vim (or gvim) has not discarded this region, but instead has placed it in a buffer.

Move to the desired transfer point, just before Insert() (black cursor, 3rd line in the screen):

Now hit p ("paste"), and the buffer contents will be placed at the cursor, thus transfering those lines of code.

If we wanted to merely copy those lines of code, not move them, we could have deleted the block and then used p twice: First at the point of deletion, to restore the block, and then at the place at which we want to copy the block.

In gvim, the GUI version of vim, it is even easier to define the region, simply by dragging the mouse.

Visual-block operations, e.g. commenting in/out code:

The v operation is oriented to sets of lines. By contrast, ctrl-v , which invokes visual-block mode, allows you to define rectangular blocks of characters.

Say for instance that we wish to de-indent the body of the function ProcessData() by 3 spaces. First, position the cursor at the beginning of the body:

Now hit ctrl-v, and then move the cursor 3 spaces to the right, and down 3 lines. This defines a highlighted region:

Now hit d to delete the region, and voila! -- the lines have been de-indented 3 spaces:

Another application of ctrl-v is the commenting out/in of lines of code. During the debugging of a program, a programmer will often temporarily "comment out" some lines of code. We can expedite this using ctrl-v, say to comment-out the innermost if-then-else within the while loop in Insert(). First, define region consisting of the first character in each line:

(Don't hit the Esc key yet.)

Now hit I. This puts you into vim's Insert mode, at the top of the highlighted region. Now enter // to comment-out the first line:

Now hit Esc to end Insert mode as usual -- and look, all the lines are commented out!

Later, we will want to re-enable those lines. Again, set up a region using ctrl-v, this time 2 columns wide:

Now hit d, to delete the comment symbols:

As you know, good programming style includes indenting lines to highlight for and while loops, if-then-else constructs, and so on. But don't indent by holding down that space bar! There are much better ways to do this if you have a good editor.

First, there is auto-indent mode, which you can set using the vim command

:set ai

In this mode, whenever you hit Enter to start typing on the next line, vim automatically will indent to the same amount as the previous line.

For example, note the position of the black cursor at the end of the 7th line of code in this screen:

After hitting Enter, the screen now looks like this:

This saved us the trouble of holding down the Space bar for 12 spaces. We can start typing the new line right away, already properly indented.

If we want to ignore this indenting on this line, we just hit the Esc key. If we want to leave auto-indent mode entirely, we type:set noai.

Another powerful auto-indenting comment in vim is the = command. We will not discuss it here, though.

Invoking the compiler, dealing with compilation errors:

In vim, type

:make

The makefile will be executed, and if there are any errors in syntax, etc. reported by the compiler, vim will relay them to you in the same window as the source code.

For instance, suppose we had forgotten to end the line

X[I] = atoi(AV[I+1])

in GetArgs() with a semicolon. After typing :make we would see the following screen:

When we then do hit the Enter key as requested, vim will move the cursor right to the location of the first error (black cursor on the 6th line of the screen):

Suppose you are typing some program source code into a file, and you have a long variable name, say OverallSalesTotal. Instead of typing that by hand every time, you can save yourself typing by setting up an abbreviation and telling your about it. In vi clones such as vim, for instance, you can do something like

:abb ost OverallSalesTotal

and from then on, whenever you type "ost" (followed by a space), the editor will automatically expand this to "OverallSalesTotal" for you. This not only saves time, but also again allows you to concentrate better on your programming, instead of being distracted.

Another way to do this is to use vim's word completion capability. Suppose I wish to type OverallSalesTotal as above, but I feel it would be too difficult to remember an abbreviation for each of the many variable and function names I have in my program. What I can do instead is use word completion:

I simply type enough of the word to make it unique. It may be, say, that this is OverallSalesTotal is the only word in my file which begins with "Ov". If so, I can type

Ov^n

where here ^n" means ctrl-n. This tells vim to complete "Ov" to the next word in the file which begins with "Ov", which will be OverallSalesTotal.

Of course, word completion is handy even when editing text files, say when composing e-mail. All of the editors mentioned at the outset of this document -- vim, emacs and jEdit -- have this feature. In emacs, for example, it is invoked as C-M / (this is emacs notation for first hitting and releasing the Ctrl key, then the Esc key, then /).

Parentheses/braces matching:

A common problem in editing program files is that we don't match parentheses or braces properly. Suppose for example in Lnk.c we had forgotten to put in the closing brace in the last else clause within Insert():

Upon running :make, we find:

Hmm...gcc thinks that at what we intended as the definition of ProcessData(), Insert()'s definition was not finished yet. So, let's move the cursor to the brace which will had intended to close Insert():

Now, let's use vim's % command to see which left brace this right brace matches:

Aha! The right brace pairs up with the opening brace of the while loop, not the opening brace of Insert(). In other words, there is a right brace missing somewhere in the loop. A little inspection reveals that it is the closing brace of the second else.

Syntax coloring:

Many editors will display different items in a program source file according to a syntax color code. In the examples here, all types, e.g. int, have been displayed in green, all executable operations such as if in yellow, all variable names in black, and so on. We got this from vim by typing

:syntax on

It is a popular feature in many programmer-oriented editors.

After you become adept at using the various tricks in a given editor, say vim, why let all that go to waste in your other editing tasks, e.g. e-mail? It makes g ood sense to use the same editor for all your work.

Thus it would be nice to have whatever editor you use for programming work, say vim, as your default editor in your e-mail utility, say pine. That means that whenever your compose a new e-mail message or reply to one you receive, your e-mail utility will automatically invoke vim for your editing pleasure.

I personally use the mutt e-mail utility, and I strongly recommend it. But most of you use pine, so here is how to make vim your default editor in pine: When your first invoke pine, first choose S (Setup), then C (configure. Scroll through the choices there until you get to enable-alternate-editor-implicitly; there just type x and an X will appear in the box. (If you check the wrong box by mistake, just type x again to make it disapear.) Then continue to scroll though the choices until you come to "editor". At that point choose C (Change Val) and type vim. Then choose E (Exit Config) and answer y when asked whether to Commit. From this point on, vim will automatically pop up whenever you compose a new message or reply to an existing one. When you are done composing your message, simply exit vim with ZZ and then send the message as usual.