Often you type the same long phrases over and over in a file.
have a number of different ways of saving long
sequences of commands, both in command mode and in insert mode.
When you call up one of these saved sequences to execute
it, all you do is type a few characters (or even only one), and the
entire sequence is executed as if you had entered the whole sequence
of commands one by one.
You can define abbreviations that vi
expand into the full text whenever you type the abbreviation in insert mode.
To define an abbreviation, use the ex
is an abbreviation for the specified
The sequence of characters that make up the abbreviation will be
expanded in insert mode only if you type it as a full word;
will not be expanded within a word.
Suppose in the file practice
you want to enter text that
contains a frequently recurring phrase such as a difficult product
or company name. The command:
:ab imrc International Materials Research Center
abbreviates International Materials Research Center
to the initials imrc
Now whenever you type imrc
in insert mode,
expands to the full text.
Abbreviations expand as soon as you press a non-alphanumeric character
(e.g., punctuation), a space, a carriage return, or
(returning to command mode).
When you are choosing abbreviations, choose combinations of
characters that don't ordinarily occur while you are typing text.
If you create an abbreviation that ends up expanding in places
where you don't want it to, you can disable the abbreviation by
To list your currently defined abbreviations, type:
The characters that compose your abbreviation
cannot also appear at the end of your phrase.
For example, if you issue the command:
:ab PG This movie is rated PG
you'll get the message "No tail recursion,"
and the abbreviation won't be set.
The message means that you have tried to define something that will
expand itself repeatedly, creating an infinite loop.
If you issue the command:
:ab PG the PG rating system
you may or may not produce an infinite loop, but in either case
you won't get a warning message.
For example, when the above command was tested on a System V version
of UNIX, the expansion worked.
on a Berkeley version,
the abbreviation expanded repeatedly, like this:
the the the the the ...
until a memory error occurred and vi
When tested, we obtained the following results
on these vi
- Solaris 2.6 vi
The tail recursive version is not allowed, while the version
with the name in the middle of the expansion only expands once.
Both versions exceed an internal expansion limit, the
expansion stops, and nvi
produces an error message.
The tail recursive version runs infinitely until the editor is
interrupted. The version with the name in the middle eventually
stops expanding, but without any error message.
5.0 and 5.1
Both forms are detected and only expand once.
7.4 and 8.0
Both forms are detected and only expand once.
We recommend that you avoid repeating your abbreviation
as part of the defined phrase.
While you're editing, you may find that you are using a command sequence
frequently, or you may occasionally use a very complex command
To save yourself keystrokes, or the time that it takes
to remember the sequence, you can assign the sequence to an unused key
by using the
command acts a lot like
except that you define a macro for vi
mode instead of for insert mode.
Define character x
as a sequence
of editing commands.
Disable the sequence
defined for x
List the characters that are currently mapped.
Before you can start creating your own maps, you need to know the
keys not used in command mode that are available for user-defined
g K q V v
- Control keys
^A ^K ^O ^W ^X
_ * \ =
is used by vi
if Lisp mode is set,
and to do text formatting by several of the clones.
In many modern versions of vi
is equivalent to the
have a "visual mode" that uses the
keys. The moral is to test
your version carefully.
Depending on your terminal, you may also be able to associate map
sequences with special function keys.
With maps you can create simple or complex command sequences.
As a simple example, you could define a command to reverse the order of
, with the cursor as shown:
you can t
he scroll page
the sequence to put the
; move to the end of next word,
; move one space to the right,
put the deleted word there,
. Saving this sequence:
:map v dwelp
enables you to reverse the order of two words at any time in the editing
session with the single keystroke
Note that when defining a map, you cannot simply type certain keys,
as part of the command to be mapped, because
these keys already have meaning within ex
If you want to include one of these keys as part of the command
sequence, you must escape the normal meaning
by preceding the key with [CTRL-V]
appears in the map as the ^ character.
Characters following the
do not appear as you expect.
For example, a carriage return appears as
, escape as
, backspace as
, and so on.
On the other hand, if you want to use a control character as the
character to be mapped,
in most cases all you have to do is hold down the
key and press the letter key at the same time.
So, for example, all you need to do in order to map
is to type:
There are, however, three control characters that must be
escaped with a
. They are
So, for example, if you want to map
, you must type:
The use of
applies to any ex
command, not just a map command.
This means that you can type a carriage return in an abbreviation
or a substitution command. For example, the abbreviation:
:ab 123 one^Mtwo^Mthree
expands to this:
(Here we show the sequence
, the way it would appear on your screen.)
You can also globally add lines at certain locations.
:g/^Section/s//As you recall, in^M&/
inserts, before all lines beginning with the word Section
a phrase on a separate line. The
restores the search pattern.
one character always has special meaning in ex
even if you try to quote it with
Recall that the vertical bar (
has special meaning as a separator of multiple ex
You cannot use a vertical bar in insert mode maps.
Now that you've seen how to use
to protect certain keys inside ex
commands, you're ready to
define some powerful map sequences.
Assume that you have a glossary with entries like this:
map - an ex command which allows you to associate
a complex command sequence with a single key.
You would like to convert this glossary list to troff
format, so that it looks like this:
.IP "map" 10 n
An ex command...
The best way to define a complex map is to do the edit once manually,
writing down each keystroke that you have to type.
Then recreate these keystrokes as a map.
You want to:
Insert the MS macro for an indented paragraph at the beginning of the line.
Insert the first quotation mark as well (
to terminate insert mode.
Move to the end of the first word (
) and add a second
followed by a space and the size of the indent (
to insert a new line.
to terminate insert mode.
Remove the hyphen and two surrounding spaces (
) and capitalize the next word (~).
That will be quite an editing chore if you have to repeat it more
than just a few times.
you can save the entire sequence so that it
can be re-executed with a single keystroke:
:map g I.IP "^[ea" 10n^M^[3x~
Note that you have to "quote" both the
is the sequence that appears when you type
is the sequence shown when you type
Now, simply typing
will perform the entire series of edits.
At a slow baud rate you can actually see the edits happening individually.
At a fast baud rate it will seem to happen by magic.
Don't be discouraged if your first attempt at key mapping fails.
A small error in defining the map can give very different results
from the ones you expect.
to undo the edit, and try again.
These examples will give you an idea of the clever
shortcuts possible when defining keyboard maps:
Add text whenever you move to the end of a word:
:map e ea
Most of the time, the only reason you want to move to the end of
a word is to add text. This map sequence puts you in insert mode
Note that the mapped key,
, has meaning in vi
You're allowed to map a key that is already used by vi
but the key's normal function will be unavailable as long
as the map is in effect. This isn't so bad in this case, since
command is often identical to
Transpose two words:
:map K dwElp
We discussed this sequence earlier in the chapter, but now
you need to use
(assume here, and in the remaining examples,
command is mapped to
Remember that the cursor begins on the first of the two words.
Unfortunately, because of the
command, this sequence
(and the earlier version)
doesn't work if the two words are at the end of a line:
during the sequence, the cursor ends up at the end of the line,
cannot move further right.
Here's a better solution:
:map K dwwP
You could also use
Save a file and edit the next one in a series:
:map q :w^M:n^M
Notice that you can map keys to ex
commands, but be sure
to finish each ex
command with a carriage return.
This sequence makes it easy to move from one file to the next
and is useful when you've opened many short files with one vi
command. Mapping the letter
remember that the sequence is similar to a "quit."
emboldening codes around a word:
:map v i\fB^[e\fP^[
This sequence assumes that the cursor is at the beginning of the
word. First, you enter insert mode, then you type the code for the
bold font. In map commands, you don't need to type two backslashes to
produce one backslash. Next, you return to command mode
by typing a "quoted"
Finally, you append the closing troff
code at the
end of the word, and you return to command mode.
Notice that when we appended to the end of the word,
we didn't need to use
, since this sequence is itself
mapped to the single letter
This shows you that map sequences are allowed to contain
other mapped commands. (The ability to use nested map sequences is
controlled by vi
option, which is normally
emboldening codes around a word, even when the
cursor is not at the beginning of the word:
:map V lbi\fB^[e\fP^[
This sequence is the same as the previous one, except that it
handle the additional task of positioning the cursor at the
beginning of the word. The cursor might be in the middle of the
word, so you want to move to the beginning with the
command. But if the cursor were already at the beginning of the
command would move the cursor to the previous
word instead. To guard against that case,
before moving back with
, so that
the cursor never starts on the first letter of the word.
You can define variations of this sequence by replacing the
In all cases, though, the
command prevents this sequence
from working if the cursor is at the end of a line.
(You could append a space to get around this.)
Repeatedly find and remove parentheses from around a word or phrase:
:map = xf)xn
This sequence assumes that you first
found an open parenthesis, by typing
If you choose to remove the parentheses, then use the map command:
delete the open parenthesis with
, find the
closing one with
, delete it with
then repeat your search for an open parenthesis with
If you don't want to remove the parentheses (for example,
if they're being used correctly), then don't use the map command:
instead to find the next open parenthesis.
You could also modify the map sequence above to handle matching
pairs of quotes.
Place C/C++ comments around an entire line:
:map g I/* ^[A */^[
This sequence inserts
at the line's beginning
at the line's end.
You could also map a substitute command to do the same thing:
:map g :s;.*;/* & */;^M
Here, you match the entire line (with
), and when you
replay it (with
), you surround the line with the
comment symbols. Note the use of semicolon delimiters, to avoid
having to escape the
in the comment.
Safely repeat a long insertion:
:map ^J :set wm=0^M.:set wm=10^M
We mentioned in Chapter 2, Simple Editing
occasionally has difficulty repeating long insertions
of text when
This map command is a useful workaround. It temporarily turns off
the wrapmargin (by setting it to 0), gives the repeat command, and
then restores the wrapmargin.
Note that a map sequence can combine ex
In the previous example,
is a vi
command (it moves the cursor
down a line), this key is safe to map because
it's really the same as the
There are many keys that either perform the same tasks as other
keys or that are rarely used. However, you should be familiar
with the vi
commands before you boldly disable
their normal use by using them in map definitions.
Normally, maps apply only to command mode -- after all, in insert mode,
keys stand for themselves and shouldn't be mapped as commands.
However, by adding an exclamation mark (
) to the
you can force it to override the ordinary meaning of a key and produce
the map in insert mode. This feature is useful when you find
yourself in insert mode but need to escape briefly to command
mode, run a command, and then return to insert mode.
For example, suppose you just typed a word but forgot to
italicize it (or place quotes around it, etc.).
You can define this map:
:map! + ^[bi<I>^[ea</I>
Now, when you type a
at the end of a word, you will surround
the word with HTML italicization codes. The
won't show up
in the text.
The sequence above escapes to command mode (
backs up to insert the first code (
escapes again (
), and moves ahead to append the
second code (
Since the map sequence
begins and ends in insert mode, you can continue entering text after
marking the word.
Here's another example.
Suppose that you've been typing your text, and you realize
that the previous line should have ended with a colon.
You can correct that by defining this map sequence:[
:map! % ^[kA:^[jA
Now, if you type a
anywhere along your current line,
you'll append a colon to the end of the previous line.
This command escapes to command mode, moves up a line, and
appends the colon (
). The command then
moves down to the line you were on,
and leaves you in insert mode (
Note that we wanted to use uncommon characters (
) for the previous map commands.
When a character is mapped for insert mode, you
can no longer type that character as text.
To reinstate a character for normal typing, use the command:
is the character that was previously mapped for
will expand x
command line as you type it, making it look like you are unmapping the expanded
text, it will correctly unmap the character.)
Insert-mode mapping is often more
appropriate for tying character strings to special keys
that you wouldn't otherwise use.
It is especially useful with programmable function keys.
Many terminals have programmable function keys
(which are faithfully emulated by today's terminal emulators
on bitmapped workstations).
You can usually set
up these keys to print whatever character or characters you want using
a special setup mode on the terminal.
However, keys programmed using a terminal's setup mode only work on
that terminal; they may also
limit the action of programs that want to
set up those function keys themselves.
allows you to map function keys by number, using the syntax:
for function key number 1, and so on.
(It can do this because the
editor has access to the entry for that terminal found in either the
database and knows the
escape sequence normally put out by the function key.)
As with other keys, maps apply by default to command mode, but by
commands as well, you can define two separate
values for a function key -- one to be used in command mode, the other in
For example, if you are an HTML user, you might
want to put font-switch codes on function keys.
:map #1 i<I>^[
:map! #1 <I>
If you are in command mode, the first function key will enter insert
mode, type in the three characters
, and return to command mode.
If you are already in insert mode,
the key will simply type the
three-character HTML code.
If function keys have been redefined in the terminal's setup
syntax might not work since the function keys no longer put
out the expected control
or escape sequence as described in its terminal database entry.
You will need to examine the terminfo
for your terminal and check the definitions for the function keys.
In addition, there are some terminals whose function keys perform only
local actions and don't actually send any characters to the computer.
Such function keys can't be mapped.
The terminal capabilities
describe the first ten function keys.
describe the remaining function keys.
Using your terminal's setup mode, you can change the control
or escape sequence output by the function key to correspond with
(For more information, see termcap & terminfo
published by O'Reilly & Associates.)
If the sequence contains
, which is a carriage return,
For instance, in order to have function key 1 available for
mapping, the terminal database entry for your terminal must
have a definition of
, such as:
In turn, the definition:
must be what is output when you press that key.
To see what the function key puts out, use the od
command with the
option (show each character).
You will need to press
after the function key, and then
to get od
to print the information.
0000000 033 [ [ A \n
Here, the function key sent Escape, two left brackets,
and an A
Many keyboards have special keys, such as
that duplicate commands in vi
If the terminal's terminfo
will be able to recognize these keys.
But if it isn't, you can use the
command to make them
available to vi
These keys generally send an escape sequence to the computer -- an
escape character followed by a string of one or more other characters.
In order to trap the escape, you should press
pressing the special key in the map.
For example, to map the
key on the keyboard of an IBM PC to a reasonable vi
you might define the following map:
This appears on your screen as:
:map ^[[H 1G
Similar map commands display as follows:
:map ^[[Y G
:map ^[[V ^F
:map ^[[U ^B
You'll probably want to place these maps in your .exrc
Note that if a special key generates a long escape sequence
(containing multiple non-printing characters),
quotes only the initial escape
character, and the map doesn't work.
You will have to find the entire escape sequence (perhaps
from the terminal manual) and type it in manually, quoting at the
appropriate points, rather than simply pressing
and then the key.
Mapping multiple key strokes is not restricted just to function keys.
You can also map sequences of regular keystrokes.
This can help make it easier to enter certain kinds of text, such
as SGML or HTML.
Here are some
commands, thanks to Jerry Peek,
co-author of O'Reilly's
Learning the UNIX Operating System
which make it easier to enter SGML markup. (The lines beginning
with a double quote are comments. This is discussed below in
Section 7.4.4, "Comments in ex Scripts "
" ADR: need this
map! =b </emphasis>^[F<i<emphasis role=bold>
map =B i<emphasis role=bold>^[
map =b a</emphasis>^[
" Move to end of next tag:
map! =e ^[f>a
map =e f>
" footnote (tacks opening tag directly after cursor in text-input mode):
map! =f <footnote>^M<para>^M</para>^M</footnote>^[kO
" Italics ("emphasis"):
map! =i </emphasis>^[F<i<emphasis>
map =I i<emphasis>^[
map =i a</emphasis>^[
map! =p ^[jo<para>^M</para>^[O
map =P O<para>^[
map =p o</para>^[
map! *l <
Using these commands, to enter a footnote you would enter insert mode,
would then insert the opening
and closing tags, and leave you in insert mode between them:
All the world's a stage.<footnote>
Needless to say, these macros proved quite useful during the
development of this book.
Named buffers provide yet another way to create "macros" -- complex
command sequences that you can repeat with only a few keystrokes.
If you type a command line in your text (either a vi
or an ex
command preceded by a colon
), then delete it
into a named buffer, you can execute the contents of that buffer with
For example, open a new line and enter:
This will appear as:
on your screen.
again to exit insert mode, then delete the line
Now whenever you place the cursor at the beginning of a word and
, that word in your text will be changed to
is interpreted as a vi
a dot (.) will repeat the entire sequence, even if the buffer
contains an ex
repeats the last
be used to undo the effect of
This is a simple example.
@-functions are useful because they can be adapted to very specific
They are especially useful when you are editing between files, because
you can store the commands in their named buffers
and access them from any file you edit.
@-functions are also useful in combination with the global
replacement commands discussed in Chapter 6, Global Replacement
You can also execute text saved in a buffer from ex
In this case, you would enter an ex
it into a named buffer, and then use the
colon prompt. For example, enter the following text:
ORA publishes great books.
ORA is my favorite publisher.
1,$s/ORA/O'Reilly \& Associates/g
With your cursor on the last line, delete the command into the
Move your cursor to the first line:
Then execute the buffer from the colon command line:
Your screen should now look like this:
O'Reilly & Associates publishes great books.
O'Reilly & Associates is my favorite publisher.
Some versions treat
when used from the ex
In addition, if the buffer character supplied after the
the command will be taken from the default (unnamed) buffer.