6.  Special topics

6.1.  Editing on slow terminals

      When you are on a slow terminal, it is important to limit the amount of output which is generated to your screen so that you will not suffer long delays, waiting for the screen to be refreshed. We have already pointed out how the editor optimizes the updating of the screen during insertions on dumb terminals to limit the delays, and how the editor erases lines to @ when they are deleted on dumb terminals.

      The use of the slow terminal insertion mode is controlled by the slowopen option. You can force the editor to use this mode even on faster terminals by giving the command :se slowCR. If your system is sluggish this helps lessen the amount of output coming to your terminal. You can disable this option by :se noslowCR.

      The editor can simulate an intelligent terminal on a dumb one. Try giving the command :se redrawCR. This simulation generates a great deal of output and is generally tolerable only on lightly loaded systems and fast terminals. You can disable this by giving the command :se noredrawCR.

      The editor also makes editing more pleasant at low speed by starting editing in a small window, and letting the window expand as you edit. This works particularly well on intelligent terminals. The editor can expand the window easily when you insert in the middle of the screen on these terminals. If possible, try the editor on an intelligent terminal to see how this works.

      You can control the size of the window which is redrawn each time the screen is cleared by giving window sizes as argument to the commands which cause large screen motions:

:  /  ?  [[  ]]  `  '
Thus if you are searching for a particular instance of a common string in a file you can precede the first search command by a small number, say 3, and the editor will draw three line windows around each instance of the string which it locates.

      You can easily expand or contract the window, placing the current line as you choose, by giving a number on a z command, after the z and before the following RETURN, . or -. Thus the command z5. redraws the screen with the current line in the center of a five line window.**

      If the editor is redrawing or otherwise updating large portions of the display, you can interrupt this updating by hitting a DEL or RUB as usual. If you do this you may partially confuse the editor about what is displayed on the screen. You can still edit the text on the screen if you wish; clear up the confusion by hitting a ^L; or move or search again, ignoring the current state of the display.

      See section 7.8 on open mode for another way to use the vi command set on slow terminals.

6.2.  Options, set, and editor startup files

      The editor has a set of options, some of which have been mentioned above. The most useful options are given in the following table.

      The options are of three kinds: numeric options, string options, and toggle options. You can set numeric and string options by a statement of the form

set opt=val
and toggle options can be set or unset by statements of one of the forms
set opt
set noopt
Name         Default               Description
autoindent   noai                  Supply indentation automatically
autowrite    noaw                  Automatic write before :n, :ta, ^, !
ignorecase   noic                  Ignore case in searching
lisp         nolisp                ( { ) } commands deal with S-expressions
list         nolist                Tabs print as ^I; end of lines marked with $
magic        nomagic               The characters . [ and * are special in scans
number       nonu                  Lines are displayed prefixed with line numbers
paragraphs   para=IPLPPPQPbpP LI   Macro names which start paragraphs
redraw       nore                  Simulate a smart terminal on a dumb one
sections     sect=NHSHH HU         Macro names which start new sections
shiftwidth   sw=8                  Shift distance for <, > and input ^D and ^T
showmatch    nosm                  Show matching ( or { as ) or } is typed
slowopen     slow                  Postpone display updates during inserts
term         dumb                  The kind of terminal you are using.
These statements can be placed in your EXINIT in your environment, or given while you are running vi by preceding them with a : and following them with a CR.

      You can get a list of all options which you have changed by the command :setCR, or the value of a single option by the command :set opt?CR. A list of all possible options and their values is generated by :set allCR. Set can be abbreviated se. Multiple options can be placed on one line, e.g. :se ai aw nuCR.

      Options set by the set command only last while you stay in the editor. It is common to want to have certain options set whenever you use the editor. This can be accomplished by creating a list of ex commands** which are to be run every time you start up ex, edit, or vi. A typical list includes a set command, and possibly a few map commands. Since it is advisable to get these commands on one line, they can be separated with the | character, for example:

set ai aw terse|map @ dd|map # x
which sets the options autoindent, autowrite, terse, (the set command), makes @ delete a line, (the first map), and makes # delete a character, (the second map). (See section 6.9 for a description of the map command) This string should be placed in the variable EXINIT in your environment. If you use the shell csh, put this line in the file .login in your home directory:
setenv EXINIT 'set ai aw terse|map @ dd|map # x'
If you use the standard shell sh, put these lines in the file .profile in your home directory:
EXINIT='set ai aw terse|map @ dd|map # x'
export EXINIT
Of course, the particulars of the line would depend on which options you wanted to set.

6.3.  Recovering lost lines

      You might have a serious problem if you delete a number of lines and then regret that they were deleted. Despair not, the editor saves the last 9 deleted blocks of text in a set of numbered registers 1-9. You can get the n'th previous deleted text back in your file by the command "np. The " here says that a buffer name is to follow, n is the number of the buffer you wish to try (use the number 1 for now), and p is the put command, which puts text in the buffer after the cursor. If this doesn't bring back the text you wanted, hit u to undo this and then . (period) to repeat the put command. In general the . command will repeat the last change you made. As a special case, when the last command refers to a numbered text buffer, the . command increments the number of the buffer before repeating the command. Thus a sequence of the form

will, if repeated long enough, show you all the deleted text which has been saved for you. You can omit the u commands here to gather up all this text in the buffer, or stop after any . command to keep just the then recovered text. The command P can also be used rather than p to put the recovered text before rather than after the cursor.

6.4.  Recovering lost files

      If the system crashes, you can recover the work you were doing to within a few changes. You will normally receive mail when you next login giving you the name of the file which has been saved for you. You should then change to the directory where you were when the system crashed and give a command of the form:

% vi -r name
replacing name with the name of the file which you were editing. This will recover your work to a point near where you left off.**

      You can get a listing of the files which are saved for you by giving the command:

% vi -r
If there is more than one instance of a particular file saved, the editor gives you the newest instance each time you recover it. You can thus get an older saved copy back by first recovering the newer copies.

      For this feature to work, vi must be correctly installed by a super user on your system, and the mail program must exist to receive mail. The invocation ``vi -r'' will not always list all saved files, but they can be recovered even if they are not listed.

6.5.  Continuous text input

      When you are typing in large amounts of text it is convenient to have lines broken near the right margin automatically. You can cause this to happen by giving the command :se wm=10CR. This causes all lines to be broken at a space at least 10 columns from the right hand edge of the screen.

      If the editor breaks an input line and you wish to put it back together you can tell it to join the lines with J. You can give J a count of the number of lines to be joined as in 3J to join 3 lines. The editor supplies white space, if appropriate, at the juncture of the joined lines, and leaves the cursor at this white space. You can kill the white space with x if you don't want it.

6.6.  Features for editing programs

      The editor has a number of commands for editing programs. The thing that most distinguishes editing of programs from editing of text is the desirability of maintaining an indented structure to the body of the program. The editor has a autoindent facility for helping you generate correctly indented programs.

      To enable this facility you can give the command :se aiCR. Now try opening a new line with o and type some characters on the line after a few tabs. If you now start another line, notice that the editor supplies white space at the beginning of the line to line it up with the previous line. You cannot backspace over this indentation, but you can use ^D key to backtab over the supplied indentation.

      Each time you type ^D you back up one position, normally to an 8 column boundary. This amount is settable; the editor has an option called shiftwidth which you can set to change this value. Try giving the command :se sw=4CR and then experimenting with autoindent again.

      For shifting lines in the program left and right, there are operators < and >. These shift the lines you specify right or left by one shiftwidth. Try << and >> which shift one line left or right, and <L and >L shifting the rest of the display left and right.

      If you have a complicated expression and wish to see how the parentheses match, put the cursor at a left or right parenthesis and hit %. This will show you the matching parenthesis. This works also for braces { and }, and brackets [ and ].

      If you are editing C programs, you can use the [[ and ]] keys to advance or retreat to a line starting with a {, i.e. a function declaration at a time. When ]] is used with an operator it stops after a line which starts with }; this is sometimes useful with y]].

6.7.  Filtering portions of the buffer

      You can run system commands over portions of the buffer using the operator !. You can use this to sort lines in the buffer, or to reformat portions of the buffer with a pretty-printer. Try typing in a list of random words, one per line and ending them with a blank line. Back up to the beginning of the list, and then give the command !}sortCR. This says to sort the next paragraph of material, and the blank line ends a paragraph.

6.8.  Commands for editing LISP

      If you are editing a LISP program you should set the option lisp by doing :se lispCR. This changes the ( and ) commands to move backward and forward over s-expressions. The { and } commands are like ( and ) but don't stop at atoms. These can be used to skip to the next list, or through a comment quickly.

      The autoindent option works differently for LISP, supplying indent to align at the first argument to the last open list. If there is no such argument then the indent is two spaces more than the last level.

      There is another option which is useful for typing in LISP, the showmatch option. Try setting it with :se smCR and then try typing a `(' some words and then a `)'. Notice that the cursor shows the position of the `(' which matches the `)' briefly. This happens only if the matching `(' is on the screen, and the cursor stays there for at most one second.

      The editor also has an operator to realign existing lines as though they had been typed in with lisp and autoindent set. This is the = operator. Try the command =% at the beginning of a function. This will realign all the lines of the function declaration.

      When you are editing LISP,, the [[ and ]] advance and retreat to lines beginning with a (, and are useful for dealing with entire function definitions.

6.9.  Macros

      Vi has a parameterless macro facility, which lets you set it up so that when you hit a single keystroke, the editor will act as though you had hit some longer sequence of keys. You can set this up if you find yourself typing the same sequence of commands repeatedly.

      Briefly, there are two flavors of macros:

Ones where you put the macro body in a buffer register, say x. You can then type @x to invoke the macro. The @ may be followed by another @ to repeat the last macro.
You can use the map command from vi (typically in your EXINIT) with a command of the form:
:map lhs rhsCR
mapping lhs into rhs. There are restrictions: lhs should be one keystroke (either 1 character or one function key) since it must be entered within one second (unless notimeout is set, in which case you can type it as slowly as you wish, and vi will wait for you to finish it before it echoes anything). The lhs can be no longer than 10 characters, the rhs no longer than 100. To get a space, tab or newline into lhs or rhs you should escape them with a ^V. (It may be necessary to double the ^V if the map command is given inside vi, rather than in ex.) Spaces and tabs inside the rhs need not be escaped.

      Thus to make the q key write and exit the editor, you can give the command

:map q :wq^V^VCR CR
which means that whenever you type q, it will be as though you had typed the four characters :wqCR. A ^V's is needed because without it the CR would end the : command, rather than becoming part of the map definition. There are two ^V's because from within vi, two ^V's must be typed to get one. The first CR is part of the rhs, the second terminates the : command.

      Macros can be deleted with

unmap lhs

      If the lhs of a macro is ``#0'' through ``#9'', this maps the particular function key instead of the 2 character ``#'' sequence. So that terminals without function keys can access such definitions, the form ``#x'' will mean function key x on all terminals (and need not be typed within one second.) The character ``#'' can be changed by using a macro in the usual way:

:map ^V^V^I #
to use tab, for example. (This won't affect the map command, which still uses #, but just the invocation from visual mode.

      The undo command reverses an entire macro call as a unit, if it made any changes.

      Placing a `!' after the word map causes the mapping to apply to input mode, rather than command mode. Thus, to arrange for ^T to be the same as 4 spaces in input mode, you can type:

:map ^T ^Vb/b/b/b/
where b/ is a blank. The ^V is necessary to prevent the blanks from being taken as white space between the lhs and rhs.