Questions regarding this article should be directed to the author at walter@ccnet.com.
Besides all the power in the Vi/Ex editor, there's a lot of flexibility in it, too. You've already met some of this adaptability when I pointed out various ways to perform many editing functions. Now it's time to meet phase two of editor flexibility -- the myriad ways to modify the editor's internal operations.
There's no ``setup mode'' for changing these parameters. Instead, all the changes are made with line-mode commands, which can be interspersed with ordinary editing commands. That is, you give the commands from the prompt, as usual, if you are editing in line mode. When you are editing in visual (or screen) mode, precede these environment-modifying commands with a colon, as you would with any other line-mode commands you specify in visual mode.
These modifications take effect as soon as you give the
commands. They stay in effect as long as you run the editor
program. You can switch from editing one file to another -- as
with any of the edit, next, rewind
commands -- without affecting the editing environment you've set
up. And, you can revoke or further modify any environmental
changes you've made at any time, by using the same commands or
variant forms of them.
Your environment setup does go away when you quit the editor altogether. The next time you invoke the editor you'll find that all the environment parameters have returned to their default values. (This can be a blessing in disguise, because there is no direct way to tell the editor to restore all parameters to default settings.)
When you've found a combination of settings you'd like to use again, there are ways to have these settings established automatically (or semi-automatically) whenever you invoke the editor. You can even have several of these preset environments -- which one is used will depend on the circumstances in which you invoke the editor. I'll explain how to automate the settings at the end of this tutorial.
set
CommandMost of your setup will be accomplished by a single command
that controls around fifty editor variables that affect the
editing environment. The set
command, for which se
is the
shortest abbreviation, sets variables having three different
types of values: string, numeric, and boolean. Consider the
examples here:
set report=7 set term=vt100 set terse set nomagic
Because the first two examples are assignments, they must
specify either string or numeric values. The first is numeric;
here, report=7
tells the editor to
give you a report (warning message) whenever a command changes
seven or more lines -- the default is five or more lines.
The second example assigns a string value; the numerals
in it are regarded as merely characters by the editor. The
term=vt100
directive tells the
editor to address your terminal as though it were a DEC model
VT100. (You specify one of the listed short names for the terminal --
obtained from the Termcap or Terminfo terminal-description
systems -- as its string value.) The default for this variable
is to use the terminal type from your log-in shell environment
(the value assigned to your TERM
variable), if
available -- and if not available, then address your terminal as
though it were a ``dumb'' terminal.
The last two examples (without equal signs) illustrate boolean
variables, which can be either on (enabled) or off (disabled). You
turn a boolean variable on just by giving its name after the
set
command. The first of these
two boolean examples tells the editor to make any error messages
very brief: cryptic to inexperienced users, but convenient for
people who are quite familiar with the editor. The default for
this variable is ``off'' or ``disabled'', which provides longer,
more explanatory error messages.
To turn a boolean variable off, just give its name prefixed by
the string ``no'' without any intervening space characters. The
last of these examples turns off the special (``magic'')
interpretation of several metacharacters, as discussed in an earlier part of this
tutorial dealing with search patterns. The usual default for
this variable's value is ``magic'', which means all
metacharacters have their special interpretation -- but if you
invoke the editor by the name edit
or vedit
, then ``nomagic'' is the
default value (no special interpretation of these particular
metacharacters).
There's no need to use several distinct
set
commands when you want to
change a number of these variables. A single command can have
almost any number of arguments. So all four of the example
commands above could be replaced by this single command:
set report=7 term=vt100 terse nomagic
Variant forms of this command will tell you the present status of individual variables, all that have been changed, or all the variables. For instance, type ``set'' without any arguments to tell the editor to display a list of all the variables that have been changed from their default values, along with their current values.
Type ``set all'' to display all the variables and their values, whether changed from default or not. This is a good way to check which variables your version of the editor recognizes, and what their default values actually are -- some proprietary versions of the editor have played with both these factors.
If you want to check the values of only one or a few variables,
you don't have to scan through a long list -- you can run a
set
command that will report the
settings of only the variables you specify. For a boolean variable,
just give the name of the variable, immediately followed by a
question mark, as an argument to the command. For a string- or
numeric-valued variable, you only need to specify the name itself,
without the equal sign. Thus, typing:
set report magic?
will produce a response like this:
report=7 nomagic
If the details of checking individual variables seem too arcane to remember, the editor will cut you some slack: You may specify the name of a boolean variable in its ``no'' form, and you may give a non-boolean variable with an unneeded question mark at the end of it, and your query will still work. So typing:
set report? nomagic?
will produce the same result as the previous query did.
You can even mix option settings with inquiries in the same
set
command, in any order. For
example, if you want to turn on
number
and set
report
to warn you whenever even
three lines are changed, and also want to know what terminal type
the editor thinks you are using and whether
terse
is on or off, any one of the
following command lines will take care of it all:
set number report=3 term terse? set term terse? number report=3 set term number terse? report=3
Below, I've listed some important editor variables that modify the visual display, with an explanation of each. If two names are specified, the first is the full name and the other is the shortest recognized abbreviation. The full name will appear in the lists displayed when you type ``set'' by itself or type ``set all''.
set
Command
Variables that Control How to Paint the Screennumber nu
You already know that the editor assigns a number to every
line in your file, and changes line numbers every time you add or
delete lines, in order to keep the numbers consecutive. The
number
boolean variable tells the
editor to display those line numbers next to every file line that
appears on the screen, in both screen and line-editing modes.
You just have to turn it on; it's off by default. If you have a
window that looks like this:
COLOR CODING FOR POWER WIRES green ground white neutral black hot red hot
turning on this variable will make it look something like this:
158 COLOR CODING FOR POWER WIRES 159 green ground 160 white neutral 161 black hot 162 red hot
The displayed numbers do not become part of the file, and nothing you can do, deliberate or accidental, will cause your editing to interact with the line numbers.
list
Turning on this off-by-default variable makes two changes in the way file lines are displayed on the screen, whether in line- or screen-editing mode:
Taking the same sample screen as in the previous example, when
the list
variable is on, the screen
would look like this:
COLOR CODING FOR POWER WIRES$ green^Iground$ white^Ineutral$ black^Ihot$ red^Ihot$
This variable affects display only, the contents of the file
are not changed in any way. The list
and number
variables are compatible.
Enabling them both would produce a display like this:
158 COLOR CODING FOR POWER WIRES$ 159 green^Iground$ 160 white^Ineutral$ 161 black^Ihot$ 162 red^Ihot$
window=
The numeric value of this variable tells the editor how many screen lines should be in the editing window (in screen-editing mode). The default is one less than the size of your screen or window. This variable's value cannot be changed while you are in screen-editing mode.
scroll
A numeric variable that sets the number of lines to be
scrolled down by a control-D or up by a control-U command. The
z
command uses twice this count as
the number of lines to display. Default value is half the size
of the screen or window.
You can give a count prior to one of those scrolling commands,
which will override the value of the
scroll
variable. For example,
typing ``3control-D'' will scroll forward just three lines.
Caution: The editor will remember any count you give,
and use that count -- instead of the value assigned to
scroll
-- with any future command
you give without specifying a new count. Because the value of
the scroll
variable remains
unchanged, even though it is no longer being used, the
set
command has no way to undo this
new behavior. The only way to go back to using the value set for
scroll
is to look up that value --
type ``set scroll'' -- then use this value as a count preceding
another of the commands that normally use the
scroll
variable.
tag
''If your editing work requires jumping from place to place in numerous files, it would be convenient to index the places you visit most. The editor has a system for handling this. It's pretty simple, too; you set up one or more reference lists, then you can go to the place within the file that you want just by typing a few characters.
Caution: the ``tags'' system described below does
not simply switch focus briefly to another file. It ends
your editing of the current file, then loads the new file into
the editor with the standard context changes, just as if you
had given an edit
command. As
a consequence of this, the editor will normally refuse to execute
a tag
command when the file you are
presently editing has changes which you have not yet written to
permanent storage. If you choose to override this protection,
give the command as tag!
or
ta!
.
To use this system, you need to set up at least one ``tags''
file containing references to your file destinations. If
programming is your work and you use C, C++, Pascal,
FORTRAN, lex or yacc, the Unix ctags
utility can set up a suitable ``tags'' file for you. If not,
it isn't all that difficult to build such a file yourself.
Each line in a ``tags'' file is a complete reference to a place you might want to go. The line has five parts, which (reading from left to right) are:
If this file structure sounds a little complex, look at this short example of a ``tags'' file to see how things actually work out:
difid ../math/calc /^APPENDIX/;/^C. Differen integ ../math/calc /^APPENDIX/;/^D. Integrals log /adm/err-log 1;?Err-7$ rvlog /adm/err-log g/^/m0|0;/Err-7$ vocab % /^GLOSSARY words % /^GLOSSARY
The first line in the example above provides that using
``difid'' as a tag will take the user to edit a file named
``calc
'', in a directory with relative path name
``../math
''. (Note: that using this tag
will not change the current directory of the user's shell; only
the file being edited is changed.) Once that file has been
loaded, the editor will seek out the first line that starts with
``APPENDIX'', and go from there to the next line that begins with
``C. Differen''.
Yes, you can specify different tags to enter the same file at different points. My second example line contains a tag that leads to a different place in the same file. After the editor has searched out the first line beginning ``APPENDIX'', as before, it goes on to a different section of the appendix.
You can even use multiple tags to enter the file at the same point, but with different preliminary editing. My ``log'' and ``rvlog'' tags go to the same file and the same line -- the most recently appended line that ends with ``Err-7''. The difference is that the ``rvlog'' tag first reverses the order of lines in the file. (Note that the search command for the two tags is different, because in the second case the line being sought has been moved to a different position in the file.)
And you can use a tag to move to a place in the file you are
already editing. In the last two example lines I have used the
percent sign (%
) to indicate
``current file''; the pound-sign (#
)
for ``alternate file'' is also acceptable. These tags move the
user to the glossary section of the document currently being
edited, whatever that document may be. If I were to invoke a
tag with an actual file name in it, and that file happened to be
the file I was presently editing, the effect would be the
same.
Finally, you undoubtedly saw that the last two entries in my tags file are identical except for the tag names. Either tag will take you to the same place in the same file with no preliminary editing. This is legitimate, and often useful. You may be building a tag file for multiple users -- some of these users are accustomed to a certain tag name for a given file and location, some to another tag name. The tags system allows you to accommodate both groups.
You may have noticed that the lines in my example file are
arranged in ASCII-sort order. This is necessary to keep the
tag-search mechanism from missing the tag you specify.
If you don't trust your own ability to sort the lines, the Unix sort
utility can do it for you.
When you've built your ``tags'' file, you need a place to put
it. Ordinarily, when you invoke a tag name, the editor first
tries to look it up in a file named ``tags
'' in your
current directory. If it fails to find such a file, it then
looks for /usr/lib/tags
. But you can override these
defaults by setting a different value for the ``tags'' file in
your editing environment. For instance, if you include this
command in your setup file:
set tags=moretags
then tag searches will take place in a file named ``moretags'' in your current directory.
With everything set up, you only need to know how to invoke a tag as needed. There are three or four ways to do it, all enumerated below:
When you invoke the editor from your shell's command line you can use the ``-t'' command-line option flag to specify a tagged item instead of naming a file to edit. For example, typing the line (from your shell prompt):
vi -t chap3
tells the editor to look up the ``chap3'' tag to find the destination file and location in that file. Oddly enough, you can list some file names to edit as well as a tag (with ``-t'') on the editor-invocation command line. The rule is that the first string of non-whitespace characters immediately following the ``-t'' flag is regarded by the editor as a tag name; any other such strings that don't begin with a ``-'' character are taken as actual names of files. However, the tagged and the named files aren't remembered the same way in this case.
For instance, if you specify a tag, then two file names,
the editor will initially place you
in the tagged file and when you type
:next
you will move to the first
named file, and another :n
(the
shortest abbreviation) takes you to the second named file. But,
the tagged file does not appear on the argument list -- viewed
with the args
command -- so when you
enter a :rewind
command you return
to the first named file, not the tagged file, even though it was
specified first on the command line.
tag
(shortest
abbreviation, ta
) followed by a
space and the tag name. This command can be given from screen
mode as :tag
, of course.Caution: A ``control-]'' is the default Telnet ``escape'' character. So if you are editing on a remote system during a Telnet session and enter a ``control-]'', control will return to Telnet, which will interpret what you type next as a Telnet command. You could change the Telnet escape character when you start your remote terminal session in order to use ``control-]'' with the editor.
:tag
command you gave in screen
mode by typing ``control-T''. This can take a count, so that
typing a ``2'' and then a ``control-T'' repeats the
:tag
command preceding the last one
you gave, etcetera.When you've worked out an editing environment setup that you will want to use frequently, or even occasionally, there is no need to type in all the changes from default every time you start up the editor. Because these are all line-mode editor commands, there are several ways to define them automatically, all or some of the time.
If there is an editor start-up file (which must be named
.exrc
) in your home directory (the dot at the start
of the name is essential and the ``rc'' abbreviation means ``run
command''), the editor will interpret it every time you invoke
the editor and execute (or at least attempt to execute) the lines
in the file as line-mode commands before it turns editing control
over to you. This applies to environment-setting commands as
well as others, so placing your set-up commands somewhere in this
file will cause the setup to happen every time you invoke the
editor.
There are drawbacks to this approach, though. You can only
have one environment preset this way: the editor will use that
same environment every time you invoke the editor. One way to
provide more flexibility is to maintain several files with
various setups in them, and before you enter the editor, rename
the appropriate one of those start-up files to .exrc
and when you leave the editor, restore its original name. But
you shouldn't have to deal with anything this cumbersome just to
control your editing environment.
The creators of the editor have provided a much better
solution. Before the editor looks in your home directory for a
start-up file, it first looks in the directory from which you
invoked the editor. If it finds a file named .exrc
there, it interprets that as the start-up file instead of the
.exrc
file in your home directory.
That behavior lets you have a special setup for each directory in which you might want to do some editing. For instance, let's say you have a directory of shell scripts, another containing chapters from a book you're writing, still another you use for writing e-mail, plus one where you store and edit error logs -- you can have a separate editing environment for each of these purposes. And if you invoke the editor from a directory where you don't maintain a separate start-up file, the one in your home directory will be used. Just remember to change to the directory where the target file(s) are located before invoking the editor.
Caution: If you invoke the editor from a directory
different from the one containing the file you're editing,
the editor will interpret the start-up file from your start-up
directory, and not use the intended environment (defined by the
.exrc
file in the directory where the target file
resides).
One caveat about multiple .exrc
files, though.
In Unix System V and its successors, a security feature restricts
the editor's access to .exrc
files that are not in
your home directory. The editor will not interpret a
.exrc
file that's not in your home directory, unless
you also have a .exrc
file that does live in your
home directory, and that file contains a line that sets the
exrc
boolean variable.
The security hazard that this complex proviso guards against
is a real one. Let's say you need to edit several files that are
in a directory like /tmp
, /var/tmp
or
some other directory that is writable by all users. To save the
trouble of providing a full path name every time you want want to
switch from one file to another, you could easily change
directories (that is, ``cd'' to the directory where these files
are located). But when you want to start editing a file, the
Vi/Ex editor may find a Trojan horse file named
.exrc
placed in your current directory by a cracker
to await victims. Of course, the commands in this false editor
start-up file will be run with your account ownership. These
commands aren't limited to editor set-up commands, but may be any
shell command that you're allowed to run, including ones to wipe
out your files, reset file permissions to allow public access to
confidential data, send indelicate comments to your boss using
utilities like write
combined with banner
,
and so forth.
Now, perhaps you work on files that have different kinds of
material in different sections, and you want to be able to make a
complete change of editing environment whenever you move from one
section to another. In this case, use the
source
command, with
so
as its shortest
abbreviation.
The source
line-mode command can
be given at any time, although you may have to give it from
line-editing mode, not from screen mode with a preceding colon. It
takes one argument, a file name or path name, and its function is
to read the named set-up file and attempt to execute the lines in
it as a series of line-mode commands.
Whether or not you can specify this command successfully in screen mode depends on the editor version you are using. Some early versions were quite serious about prohibiting multiple-line line-mode commands while in screen mode. So serious that these versions will execute only the first line of a script that has been sourced in while the user is in screen mode. If you don't encounter this behavior, you can ignore this warning. If you do, you at least know where the problem lies.
Now that you understand editor start-up files, I can
acknowledge that the one you put in you home directory is not
strictly necessary. The editor will accept the value of a shell
environment variable named EXINIT
as the string of
line-mode commands to be run whenever the editor starts up. But
I don't recommend going this route, for several reasons:
.exrc
file is practically unlimited. As
you get better at using the editor, you can easily develop a
home-directory start-up file that is too large for
EXINIT
.EXINIT
variable from
scratch.EXINIT
variable
is defined in a shell start-up file, it's new definition won't
take effect until you log-in again or explicitly ``source'' the
shell start-up file from the shell's command line.EXINIT
shell variable.You can use source
to execute an
editor set-up file from anywhere in your file space. It will
also execute any file of line-mode commands, no matter what the
file name. For example, let's say you have a special environment
setup that you never use at the beginning of an editing job, but
you do need it to edit tables. You invoke the editor as always,
but when you're ready to edit your tables, you run a command
like:
:so table-defs
where the table-defs
file contains line-mode
commands that set up the editor for table editing.
When you specify a file of line-mode editing commands with
source
to perform, say, a
frequently used edit automatically, it's probably a good idea to
have commands in that file to return the editing environment to
what it was before the editing commands were run, assuming the
environment was changed for the editing task.
Caution: If you decide to use environment set-up files
that you specify while you are editing -- you can't always depend
on default values. For example, the
autoindent
variable is disabled
(``off'') by default. So if you are setting up a start-up file
that will only be used at the beginning of editor sessions, and
you don't want to use autoindenting, you don't need to do
anything to leave it turned off. But if you plan to occasionally
use that set-up file in the middle of a session, you have to ask
yourself, ``Will I ever use this setup in a case where I
previously had autoindenting turned on, either by another set-up
file or because I manually turned it on?'' If the answer that
question is ``Yes'', then the set-up file you're writing must
contain a set noai
command to be
sure that autoindentation is definitely disabled.
And, what if the source
command
is broken in your version of the editor? There is still a way to
make semiautomatic environment changes. You have to use the
line-mode read
command plus a
little-known feature of letter-named storage buffers.
You're probably accustomed to using the ``a'' through ``z''
named buffers for storing pieces of text, and returning these
pieces to the main document with commands like
"jp
, which returns the contents of
the ``j'' buffer right after the cursor position in visual mode.
Well, you can also use a visual-mode command of the form
@j
, which takes the text from the
``j'' buffer and executes it as a visual-mode command string.
For instance, if buffer ``j'' contains ``257G3dd'' as its text,
then typing @j
will move the cursor
to line 257 and delete that line and the two that follow it.
The text in the buffer must be commands you could give from visual mode for this feature to work, but that includes line-mode commands that are preceded by a colon and terminated with a carriage-return character. So if buffer ``h'' contains the lines:
:se nomesg terse list :map v :!wc -w %^M 1G
then typing ``@h'' will reset three variables, map a command string, and move the cursor to the first line in the file.
There are a few points you should keep well in mind when you are placing line-mode commands into a letter-named buffer for future execution. All of them revolve around the fact that the editor is expecting screen-mode commands from this source.
To import this set-up command list from an outside file to the
``h'' buffer, use the read
command.
For example, if your three-line set-up file is named
set.5
, then type:
:r set.5 "h3dd@h
to read the file into your editing buffer, then the
"h3dd@h
command will delete those
three lines -- which came from the external file -- into the
``h'' named buffer, then execute the same lines as set-up
commands.
In the next part of this tutorial series I will finish up the
subject of editing environment by discussing more editor
variables, then explaining the
abbreviate
and
map
commands. Then it's on to the
treacherous albeit important topic of addresses for screen-mode
commands.