
By
Walter
Alan Zintz
.
Automatic Indentation
Computer editing is a great advance over typing on paper, the
consensus has it. But wouldn't you be happier yet if you had the
tabstop-setting capability of your old typewriter, too? With the
Vi and Ex editor, you have a feature that's just as powerful and
a lot easier to use, but not many users know it's there. Yet
there it is, on even early versions of the editor -- its name is
autoindent
.
With
autoindent
turned on, you can start a running
indent any time you are in text-insert mode -- whether initiated
from an
R
or from any other command
that starts you typing in text. Just put some whitespace at the
start of th
e first line you want indented. From then on, each
time you hit the return key, the editor will automatically insert
exactly the same amount of whitespace at the start of the next
line. That is, if you begin a line with five space characters,
every following line you type in will begin with five space
characters also; causing the left margin to line up nicely, but
five spaces in from the normal margin setting.
Note that I said ``whitespace'' above, which includes the
tab character as well as the space character. Autoindentation
works whether you start a line with spaces, or tabs, or some
combination of the two. In fact, it even understands redundant
combinations, such as starting a line with two space characters
followed by a tab character.
We both know that tabbing from two spaces in will reach the
first tabstop, as surely as tabbing from the left margin would --
those two spaces have no effect as far as where the indented line
actually starts. Autoindentation knows this too, and will st
art
each subsequent line with just a tab character. But if you
started a line with a tab followed by two space characters, then
the spaces would have an effect -- moving the margin to the right
two more character positions than the tab alone would have. In
this case, autoindentation will incorporate those two following
space characters, as well as the leading tab, into the text at
the start of each subsequent line.
The general rule is that while autoindentation will always put
in the same amount of leading whitespace that you did, or at
least try hard to do so, it may use its own discretion as to the
combination of tab and space characters it uses to do this.
If you want to increase the indentation at some point, just
type more whitespace at the beginning of an (already indented)
line, and your new indentation depth will be the rule from that
point on. You can even leave insert mode to correct a mistake
without losing the indented margin setting, providing you return
to insert mode with a
n
o
or
O
command.
Backing off Indentation
To set the indentation back (or off), you need to use the
Control-D character. When you want to stop the indentation
temporarily, for just one or a few lines, type a circumflex
(^) followed by Control-D at the start of each such line, to
move the start of just that one line back to the left margin.
If you type the numeral zero followed by control-D at the
start of a line, automatic indentation
disappears completely until you again start a line with
whitespace. This takes effect starting with the line you are on
when you type it.
To set the indentation point back to the nearest shiftwidth
(discussed below) stopping place that's to the left of your
present indent point, and leave it there until you change it
again, type just control-D at the start of the line. If that is
not enough margin reduction for you, just type several
consecutive control-D characters to get
the amount you want. This
setback also takes effect starting with the line you are on when
you type the control-D.
Juggling a few
:set
options
And that brings up the whole vexed question of lengths of tabs
and lineshifts, which are controlled by three options of the
:set
command. When you are in the
editor, type in the
:set
command
query as in the first line below, and see whether the response is
the default -- as given in the line following it:
:se sw ts ht
shiftwidth=8 tabstop=8 hardtabs=8
The first of these reflects the primary problem in using
autoindentation. The
shiftwidth
option was created
to control some commands I haven't discussed yet, which add or
subtract whitespace at the start of each line you designate;
this option sets the number of spaces these commands add or
subtract. In addition, though, the value of this option
also
determines where your left margin will land when you go back
part of the way to your window or screen's left margin.
So if your
shiftwidth
option is set to the default
value of eight spaces, as shown above, then there will be a
stopping point every eight spaces across your screen or window --
in the ninth column, in the seventeenth column, in the
twenty-fifth column, etcetera. (This presumes that you call the
leftmost character position on your window or screen column one,
which is what the editor calls it, and not column zero.) So if
your autoindented margin is in the twenty-first column, typing
control-D at the start of a line will put it back to the
seventeenth column. If the margin is presently in the eighteenth
or the twenty-fourth column, the effect would be the same. But
if the present margin is in the twenty-seventh or thirtieth
column, then a single control-D would set it back to column
twenty-five.
Of course, you can reset the
shiftwidth
value via the
:set
command. Many programmers
reset that value to four. Then the stop points will be in every
fourth column -- in column five, in column nine, in column
thirteen, in column seventeen, and so on. This reduces line wrap
in program source code with many levels of tab indentation.
Here's a visual representation of the difference: first of the
default tab stops every eight columns, then as they are when
reset to every four columns:
+-------+-------+-------+-------+-...
1 9 17 25 33
+---+---+---+---+---+---+---+---+-...
1 5 9 13 17 21 25 29 33
But you just might be creating a problem by doing this. With
identical
shiftwidth
and
tabstop
values,
backing up via a control-D requires only erasing one tab
character or erasing one or more space characters; never anything
more complex. With a
shiftwidth
value of four and a
tabstop
value of eight, though, there will be times when
a control-D
requires the editor to remove one tab from the
whitespace sequence with which it starts each line, and
simultaneously add four space characters. A few versions of the
editor cannot handle this complexity in some circumstances, and
will at times put garbage in your file. Even more likely is that
the editor will mess up when it encounters tab characters in the
middle of lines.
The
tabstop
option controls the number of spaces the
editor thinks you want between tabstops. With this option at its
default value of eight, there will be a tabstop every eight
spaces, falling in the same columns as the
shiftwidth
stop points when that option's value was also at its default
value of eight. So if you set the values of both options to
four, you will still have both options' stop points falling in
the same columns, solving the problem posed in the last
paragraph.
Solving it at quite a price, though. The editor can use your
special value of four spaces between tabstops (or any other val
ue
you choose to give) when it is inserting and removing tabs as you
type, but it has no way to mark those characters in your file to
say ``This is a four-column tab character'' and ``That is an
eight-column tab character''. Not that there is any difference
between the tab characters themselves. A tab always moves the
cursor to the next tabstop point in the line, wherever that may
be. The difference is that some of your tabs will be inserted
when you expected the editor to find a tabstop point every four
columns; others when you (or someone else) were expecting
tabstops every eight columns.
So when you set your tabs value to four and then edit a file
that was composed with tabs at their default value of eight,
indentations will be only about half as deep as the original
writer intended they should be. And when you write this file
back to permanent storage, anyone who uses the file after you and
has default tab settings will find the indentations you added to
be about twice as deep as you intended -
- this will often cause
deeply indented lines to be too long to be displayed on a single
line of the user's screen or window.
Since you've gotten this far in the tutorial, you're surely a
skilled user who can see how to get around this -- by writing a
.exrc
file entry to translate eight-column-tab
indentations into four-column-tab equivalents as you pull in a
file to edit, and a macro to do the reverse in the course of
writing your work out to permanent storage.
An Exercise for You
It was several tutorial parts ago that I last put exercises
for the reader in the tutorial itself. This seems like a good
place to revive that practice. Just how would you write a
command sequence to handle that latter operation as regards
start-of-line indentations? Let's say you edit in screen mode,
with your
tabstop
option set to a value of four, so that
a ten-column indentation consists of two tabs followed by two
spaces and a thirteen-column indent is thre
e tabs followed by one
space. But when you write the file to permanent storage, you
want it to be in the conventional format of eight columns between
tab points (at least for indentations) -- so that same ten-column
indentation will now consist of just one tab followed by two
spaces, and the thirteen-column indent will have a single tab
followed by five spaces -- to keep the indentations at the same
depth they were. What sequence of commands will accomplish
this?
To simplify the problem, assume that the curly brace
characters (``{'' and ``}'') never appear in files you edit (if
they are present, which is common for program source code, choose
another character pair) and that you will only be writing to the
original file name, let ^I stand for a real tab character when
you write your answer, and don't worry about how you would turn
your command sequence into a macro. But, definitely do remember
that you will be doing a write in the middle of your editing
session from time to time, to guard against l
osing work in a
system crash, so your command sequence must leave the file copy
in the editor buffer just as it was before you wrote the modified
version to storage, ready for you to continue editing.
This exercise is not so difficult if you've been following
this tutorial carefully. The biggest hazard for those readers is
that they may come up with a sequence that will work, but is much
longer than it needs to be. So if your solution seems long-winded,
take a look at my
hint
before you jump to my
solution
.
These translator macros will work nicely for leading
whitespace (indentations), but it would take incredibly complex
scripts (whether Vi editor scripts or scripts for most other Unix
utilities) to deal with tabs in the interiors of lines. The
pestilential problem there is that you don't know just where an
interior tab character is placed -- how many positions in from
the start of the line. For example,
when you are trying to
translate eight-column tabs into four-column equivalents, and
your macro finds a single eight-column tab in the middle of a
line, is that tab in a column that is five or more columns from
the next tab stopping point? If yes, it must be replaced by two
of the four-column tabs; if no, it is correct as it is.
Similarly, when going from four-column to eight-column tabs, a
solitary tab in the middle of a line may be left there or may
have to be replaced by space characters, depending on its column
position.
If you must do this kind of translation, your best bets are
the
-e
and
-i
options to recent
versions of the
pr
Unix command.
Running a file through this utility will make the conversions
correctly, even when the whitespace appears in the middle of
lines. The downside is that your text may be reformatted to some
degree.
Hard Tabs
And then there is the
hardtabs
option to the
:set
command. That option is
used to tell the editor how far apart the tab stopping points
are on your physical terminal -- the editor uses this information
to decide what mix of tab and space characters will represent on
your screen the indentation depth that's in your file. That is,
the editor runs its own translator program, if necessary, to
make the spacings on your screen the same depth as those in your
file. Here too, any difference between this value and either of
the previous two is likely to cause problems. It's fortunate
that any value you give to this option will be overridden by the
spacing value that is in your Termcap or Terminfo file, because a
difference between the terminal tab setting Vi expects and that
which your terminal is actually using will scramble your screen
for sure.
So my reluctant admonition to you is to leave all three of
these options set at their default values of eight. Messing
around with any of them is just too likely to cause troub
le.
Enable and Disable
autoindent
Of course, all this means that when you have autoindentation
on, the control-D, circumflex followed by control-D, and zero
followed by control-D
sequences are all metastrings at the beginning of an indented
line. To turn the metavalue off, so you can put one of these
strings into the text at the start of an indented line, quote in
the control-D character by preceding it with a control-V.
So how do you turn the whole
autoindent
mode on and off?
It's normally off when you begin an editor session, and the usual way
to turn it on is to use the
:set
command.
Just type
:se ai
to turn this feature on.
When you want to tell the editor to stop automatically indenting every
time you start a line with whitespace, type
:se
noai
(from command mode) to turn
autoindent
off again.
Autoindent also works with the line-mode
append
insert
commands, which can be abbreviated
a i
respectively. These commands
let you type in new lines of text, below or above the current
line, respectively. That is, they are generally the line-mode
equivalents of the screen-mode
o O
commands. They can only be run when you are in line mode; even
preceding one of them with a colon (``:'') will not let you run
it from screen mode.
The setting of the
autoindent
option controls
autoindentation within these text insertions, too, but there is
also another way to control it that works only with these
line-mode commands. Whenever you follow one of these commands or
its abbreviation with an exclamation point (``!''), without any
characters or space in between, you toggle the autoindention
setting for that insertion only. That is, if autoindentation was
off, the ! turns it on during this insertion. Similarly, if
autoindentation was on at the time,
the ! turns it off just for
this insertion.
[
Editor's Note
: Here's an example where it really
helps to disable autoindent. When programming, I use a simple
.exrc
file containing an
se ai bf nu sw=4
ts=4 wm=0
line. If I cut a section of indented
lines from one window and paste it into my program I get a
staircase effect as each line is inserted with one more tab than
the last. Most annoying.]
Next Time
The next part of this tutorial will cover the
:abbreviate
and
:map!
commands, both of which help
you save typing while you are in text-insertion submode.
Then, on to the editor's several facilities for creating macros
and pseudo-macros that you can use from the command submode.
And it will finish with more readers' questions and my answers,
if you readers will send me some worthwhile questions soon.
You may be laughing at that final word, ``soon''
But my secret weapon this time is that, while my editor was
away I spent some time writing about half of the next part. So,
when she returns from a week of well-deserved vacation in
mid-November, I plan to have the completed tutorial installment
waiting for her. Wish me luck.
|