Advanced Vi editing
================================================================================
Overview:  This lesson builds on the previous lesson about the "vi" file editor.
           More commands are shown, and tips and hints are given for easier,
           faster editing.
================================================================================

Section                             Topic
-------                             -----

   More cursor movements (jump by word, page)
   Overtyping
   Cutting and pasting text
   Showing line numbers
   Including files (copying lines from other files into current file)
   Repeating commands
   Dealing with long lines
   Breaking and Combining lines
   UNIX commands while in Vi
   Editing multiple files
   Searching backwards and forwards
   Line ranges
   Miscellaneous


More cursor movements
---------------------

In addition to the basic cursor movements using the arrow keys and
h, j, k, l, you can immediately jump to the last line in the file by
typing a capital G.  To immediately jump to the first line, first type
1, then a capital G.  As always, you never follow these by the RETURN
key.

Other cursor movements allow you to move forward and backward one page.
To move forward one page, hold down the CONTROL key and press F.  We
shall abbreviate this as CTL-F.  To go back one page, use CTL-B.

Moving forward one half page is often useful so that you do not lose the
context of what you were reading.  CTL-D takes you "down" or foward 1/2
page, while CTL-U (or "up") moves you to the previous 1/2 page.  In either
case, you will still see half of the page you were just looking at so
that you can continue your reading smoothly.

There are many other cursor movement commands.  To go to the beginning
of the line on which your cursor is sitting, press 0 (zero) from the
command mode.  Make sure that you do not press "O" (oh) because that
means "open up a new line".  To go to the end of the current line, press
the dollar sign, $.

If you press the RETURN key from command mode, the cursor jumps down to
the beginning of the next line.  However, it skips over any leading blanks.
If you want to go to the beginning of the line, you must press zero (0).
The RETURN key, while in insert mode, actually opens up a new line.
As always, you must know which mode you are in.  If you are in doubt,
just hit ESC.  If you were in insert mode, now you're in command mode.
If you were in command mode, vi will just beep at you but it won't harm
anything.

The "w" key is used to move forward one word, where as word is defined by
vi as any sequence of numbers or letters.  Each punctuation mark is con-
sidered one word, however.  To go back one word, use "b".  There are
variants of these commands that are used if you want to alter the definition
of a "word".  If you use "W" (capital W), vi moves forward one Word, where
a Word is defined to be any string of nonblank characters.  Thus if your
cursor is on the first slash of

        /mnt1/dept/meyer/bin xxx

and you type "w", it just goes to the first "m".  Typing "w" moves to the
second slash.  However, typing "W" will jump to "xxx", since all of the
pathname /mnt1/dept/meyer/bin is considered one Word.  "B" moves backwards
one Word.


Overtyping
----------

Normally, if you want to replace a section of text, you first delete the
old text, then go into insert mode, and type the new text.  This is often
clumsy if you are editing a table or a picture.  To overtype what is already
there, first press "R" (capital R).  Then just type your new text, which
will replace what's on the screen.  When done, press ESC.

To replace just one character, press "r" (lower case r) and then the new
character.  This is faster if you need to replace just one letter.


Cutting and pasting
-------------------

There is a special memory area called the "paste" buffer.  When you 
delete 1 or more lines, or characters, they go into this buffer.  You
can subsequently "put" them somewhere by moving the cursor to the place
where you wish to put them and typing either P or p.  In "vi", capital
letters signify that you will insert the text BEFORE the cursor, and
lower case AFTER the cursor.

You can also get text into the paste buffer without deleting it from
its original spot.  That is, you can copy some lines into the paste buffer
without disturbing their original spot.  The "yy" command does this; it
stands for "yank".  Put your cursor on the first line of the block you
wish to copy, then type the number of lines to yank, followed by yy.
If there are 500 lines, type 

    500yy

Nothing will appear on your screen, which is one of vi's weaknesses.  It
doesn't give you much visual feedback.

Now move to the new location and type "p" to put the lines.

If you wish to move some lines around in a file, you can use the "move
command instead.  For example, if you want to move lines 10 and 11 so
that they will appear after line 5, move your cursor to line 5 and type

     :10,11m.

The 10,11 is again a range or block of lines.  The "m" means move and the
dot means "the current line".


Line numbers
------------

Sometimes it is nice to see the lines' numbers at the left edge of each line
in a file.  This is true when you use the C debugger dbx.  To do this,
once you are in vi and editing a file, type the command

     :set nu

Then press RETURN.  The colon will cause your cursor to temporarily jump to 
the bottom of the screen.  All special vi commands which begin with colon
are entered at the bottom of the screen and must be ended with hitting the
RETURN key.

When the line numbers appear in the file, you will not be able to edit or
change them.  However, if you open up a new line, or delete some lines, the
line numbers adjust accordingly.  Also do not be alarmed if some of your
lines are shoved to the right edge too far, and are continued on the next
line.  They are still treated as one line even though they don't fit on the
screen.

To turn off line numbers, do

     :set nonu

Line numbers are usually off whenever you start vi.


Inclusion of files
------------------

If you are editing a document and wish to include another file in the
document, move the cursor to the line after which you wish to insert the
file.  Then type the command:

    :r filename

where "filename" is really the name of the file you wish to include.
If you make a mistake, just type "u" to undo this, or ":q!" to quit without
saving changes.

An inverse operation that is often needed is to write out certain lines of
a file that you are editing.  Let's say that you want to write out five
lines from the file that you are currently editing to a new file called
"joke".  Move your cursor to the first line and type the following command:

    :.,.+4w joke

The colon of course introduces one of the complex vi commands.  .,.+4
is actually a range of lines.  Dot (.) stands for the current line, and .+4
would be the number of the current line plus 4 down.  "w" means you want to
write this range out to file "joke".

Another way to do this is to find out the actual line numbers and specify
them in the range:

    :192,196w joke


Repeat the last command
-----------------------

The dot (.) when typed from command mode means "redo the last command".
This is a handy way to do many things, such as delete a block of lines.
For example, move your cursor to the first line you wish to delete.  Type
"dd" to delete that line.  The next line down moves up one so that your
cursor will be sitting on what was the next line.  To delete that line, too,
just press . once and it is as though you typed "dd".  You can do this any
number of times.

The dot does not redo cursor movement commands, which is actually handy
because if you want to redo the same editing command (like insert some
text or delete a line or word), just move to the next spot and press the
period key (.).


Long lines
----------

If you are editing a file and there are very long lines in it, too long
for your terminal to display, the lines will wrap around.  That is, they
will appear on your screen as multiple lines, often broken at an awkward
place, such as the middle of a word.  You can detect these lines because
if you use the "j" key to move down to the next line (or even the RETURN
key), it will skip several lines on your screen.  This happens because
"j" (which is also known as the down arrow key) means jump down to the
next line in the file, not the next line on your screen.

To edit those long lines, go to the beginning of any line (using the zero)
and then use the "j" or "k" keys to go to the long line.  Then you can use
the "l" or arrow right key to move forward.  Normally, if you hold down
the "l" key too long, the cursor will bump up against the end of the line
and vi will beep at you.  But if you are on a long line, the cursor keeps
going until it finds the end of the file's line, even if that means moving
down to the next line on the screen.  Similarly you can move backwards
with "h" or left arrow, or you can use zero or $ to move immediately to
the beginning or end of the long line.

If you want to delete a long line, your cursor must be in that
line, not necessarily at the beginning.  Just press "dd" and the long line
vanishes, which may move several lines up on the screen.  (As always "u"
undoes the deletion, so it is ok to experiment!)

Occasionally, there are so many long lines that "vi" cannot display all
of them on the screen.  If the screen ends with a part of a long line,
"vi" will show as much of the long line as it can, and will put an at-sign
(@) at the bottom to indicate that this is an incomplete display.  Moving
down with the cursor key so that the file scrolls up will display the rest
of the long line.  The @ sign is not a part of the file at all.


Breaking and combining lines
----------------------------

Let's say that you have a very long line in your file and you wish to break
it into two lines.  Move your cursor to the point where you wish to break it
and type "i" for insert.  Then, while in insert mode, just press the RETURN
key.  Now press ESC to get out of insert mode.  The line breaks where you
pressed RETURN.  (Always remember "u" undoes the last thing just in case you
made a mistake...)

To join together two adjacent lines into one longer line, move your cursor
to the first line that you wish to join and type a capital J.  The cursor
does not have to be at the end of the line.  The two lines are joined into
a long line, which may show up as one line on your screen if the original
two lines were short enough, or it may show up as a long line (see above)
if the new line is too long to fit on the screen.  But as far as the file
on disk is concerned this is now one line.


Doing commands in vi
--------------------

While editing a file in "vi", you can temporarily exit and do a UNIX command.
Just type :, followed by !, followed by the UNIX command, ending with a
RETURN.  For example, to receive your mail, do

    :!mail

Or to temporarily escape to an entirely new shell, do

    :!csh

You will get a new % prompt, and you can enter any unix commands, even 
another "vi" command, and they will not interfere with your editing session.
To leave this shell, type "exit" and press RETURN.  You cannot log out of the
system from this kind of shell.  If you try, UNIX will scold "This is not a
login shell".  This is to protect you from making mistakes like forgetting
to save the file you were editing.

If you are editing a file, and wish to switch to a different file, you can
issue a new vi command from the :
 
    :vi xxx.c

The old file will vanish and the contents of xxx.c will appear on your screen.
If you had made changes to the other file, UNIX will not let you do this,
unless you override it with an exclamation mark:

    :vi! xxx.c

or if you want to first save it, use :w, the new :vi xxx.c command.


Editing multiple files
----------------------

Vi is a very simple minded and old fashioned editor.  If you are editing a
file, you can only edit it in one place; you cannot have multiple windows
into the same edit file, as you can with many word processing systems or
fancier editors.  Also you cannot edit more than one file at a time.  You
must first save and then switch to the new file.

However, vi will let you specify a number of files to edit on the command
line.  For example, if you wish to add a line to each of your .c files 
in some directory, do:

     % vi *.c

Vi will bring up the first file, which you can edit.  When done with that
one, use :w to write it back to disk, and then :n to go to the next file.
You can always use :f to see which file you are currently editing.


Searching backwards and forwards
--------------------------------

To find a particular string of characters, use the the slash key.  This
also causes the cursor to jump down to the bottom of the screen as the colon
does.  Type your string and press RETURN and vi will search forward from
the current position of the cursor.

To find the next occurrence of this string, press "n" (no colon).  Another
way to do this is to press the slash again but rather than typing in the
word, just press RETURN.  However, this requires two keystrokes whereas
the "n" key is just one keystroke.  (One of the great things about vi is
that many tasks require just one keystroke so vi is extremely fast to use
in the hands of an experienced "vi-er".  However, without all sorts of pull-
down menus and function keys, it is hard to learn.)

If you have just found the last occurrence of your search string in the file
and you press "n", vi wraps around to the beginning of the file.  If there
is only one occurrence in the file, pressing "n" repeatedly will just show
that same line over and over.

To search backwards, use the question mark instead of the slash.  If you
type "n" after a backward search, vi finds the previous instance of the
string.  To go forward again, you must use the slash instead.  ? wraps
around to the end of the file in a manner analogous to the slash wrapping
around from the end back to the beginning.


Line ranges
-----------

As you have seen above, many vi commands need to be typed after the colon
prompt.  This is because these commands are often long and complex, and
vi doesn't know where they stop until you press the RETURN key.  Many of
these commands also use a line range.  A line range consists of two line
numbers separated by a comma.  For example:

     50,100

Line ranges usually come at the beginning of a command.  To insert blank
spaces at the beginning of lines 50-100, use the "s" or substitute command:

     :50,100s/^/     /

(The caret means "the beginning of the current line".)

There are several special conventions.  If a line range consists just of
% (the percent sign), it means "all lines in the file".  For example, to
put blanks in front of every line, use

     :%s/^/     /

To delete every line, do

     :%d

The period (.) stands for the current line, and you can reference this using
arithmetic operators, such as

     :.,.+5s/^/    /

This means put blanks at the beginning of this line and the next 5 lines.
You can also use - to indicate lines previous to the current line.

The last line in the file is always $, while the first line is always 1.

To delete all lines from a certain point to the end, move to that line
(say it is line 50).  Then enter the command

      :.,$d

which means start at the current line and delete the block of lines that
goes from here to the end.

To delete the first part of a file, move to the last line you wish to delete
(say line 50), and type

      :1,.d

This avoids needing to know specifically what line you are on, which you can
find out with :f of course.  But keeping all those line numbers in your head is
tedious.


Miscellaneous
-------------

To delete from a certain point to the end of the current line, move your
cursor to that point and type D (capital D).

To move to the next sentence, type ")".  A sentence is defined, as it 
is in English, using periods.  To go to the beginning of the previous
sentence, type "(".

The command to save and quit is either :wq or ZZ.  The ZZ version is much
faster for an experienced "vi-er" to type.

To change the case of a letter, use the tilde which is ~.  If your cursor
is on a lower case letter, ~ changes it to upper case and moves to the next
letter.  Similarly if the letter is already uppercase; it switches it to
lowercase.