iThe vi/ex Editor, Part 8: Indent, Like a Typewriter
       i
       i  Automatic Indentation
       i  Backing off Indentation
       i  Juggling some :set options
       i  An Exercise for You
       i  Hard Tabs
       i  Enable and Disable autoindent
       i  Next Time
       i
       iAutomatic Indentation
       i
       iComputer editing is a great advance over typing on paper, the
       iconsensus has it.  But wouldn't you be happier yet if you had the
       itabstop-setting capability of your old typewriter, too?  With the
       iVi and Ex editor, you have a feature that's just as powerful and a
       ilot easier to use, but not many users know it's there.  Yet there
       iit is, on even early versions of the editor -- its name is
       iautoindent.
       i
       iWith autoindent turned on, you can start a running indent any time
       iyou are in text-insert mode -- whether initiated from an R or from
       iany other command that starts you typing in text.  Just put some
       iwhitespace at the start of the first line you want indented.  From
       ithen on, each time you hit the return key, the editor will
       iautomatically insert exactly the same amount of whitespace at the
       istart of the next line.  That is, if you begin a line with five
       ispace characters, every following line you type in will begin with
       ifive space characters also; causing the left margin to line up
       inicely, but five spaces in from the normal margin setting.
       i
       iNote that I said "whitespace" above, which includes the tab
       icharacter as well as the space character.  Autoindentation works
       iwhether you start a line with spaces, or tabs, or some combination
       iof the two.  In fact, it even understands redundant combinations,
       isuch as starting a line with two space characters followed by a tab
       icharacter.
       i
       iWe both know that tabbing from two spaces in will reach the first
       itabstop, as surely as tabbing from the left margin would -- those
       itwo spaces have no effect as far as where the indented line
       iactually starts. Autoindentation knows this too, and will start
       ieach subsequent line with just a tab character.  But if you started
       ia line with a tab followed by two space characters, then the spaces
       iwould have an effect -- moving the margin to the right two more
       icharacter positions than the tab alone would have.  In this case,
       iautoindentation will incorporate those two following space
       icharacters, as well as the leading tab, into the text at the start
       iof each subsequent line.
       i
       iThe general rule is that while autoindentation will always put in
       ithe same amount of leading whitespace that you did, or at least try
       ihard to do so, it may use its own discretion as to the combination
       iof tab and space characters it uses to do this.
       i
       iIf you want to increase the indentation at some point, just type
       imore whitespace at the beginning of an (already indented) line, and
       iyour new indentation depth will be the rule from that point on.
       iYou can even leave insert mode to correct a mistake without losing
       ithe indented margin setting, providing you return to insert mode
       iwith an o or O command.
       i
       iBacking off Indentation
       i
       iTo set the indentation back (or off), you need to use the Control-D
       icharacter.  When you want to stop the indentation temporarily, for
       ijust one or a few lines, type a circumflex (^) followed by
       iControl-D at the start of each such line, to move the start of just
       ithat one line back to the left margin.  If you type the numeral
       izero followed by control-D at the start of a line, automatic
       iindentation disappears completely until you again start a line with
       iwhitespace.  This takes effect starting with the line you are on
       iwhen you type it.
       i
       iTo set the indentation point back to the nearest shiftwidth
       i(discussed below) stopping place that's to the left of your present
       iindent point, and leave it there until you change it again, type
       ijust control-D at the start of the line.  If that is not enough
       imargin reduction for you, just type several consecutive control-D
       icharacters to get the amount you want. This setback also takes
       ieffect starting with the line you are on when you type the
       icontrol-D.
       i
       iJuggling a few :set options
       i
       iAnd that brings up the whole vexed question of lengths of tabs and
       ilineshifts, which are controlled by three options of the :set
       icommand.  When you are in the editor, type in the :set command
       iquery as in the first line below, and see whether the response is
       ithe default -- as given in the line following it:
       i
       i  :se sw ts ht
       i
       i  shiftwidth=8 tabstop=8 hardtabs=8
       i
       iThe first of these reflects the primary problem in using
       iautoindentation.  The shiftwidth option was created to control some
       icommands I haven't discussed yet, which add or subtract whitespace
       iat the start of each line you designate; this option sets the
       inumber of spaces these commands add or subtract.  In addition,
       ithough, the value of this option also determines where your left
       imargin will land when you go back part of the way to your window or
       iscreen's left margin.
       i
       iSo if your shiftwidth option is set to the default value of eight
       ispaces, as shown above, then there will be a stopping point every
       ieight spaces across your screen or window -- in the ninth column,
       iin the seventeenth column, in the twenty-fifth column, etcetera.
       i(This presumes that you call the leftmost character position on
       iyour window or screen column one, which is what the editor calls
       iit, and not column zero.)  So if your autoindented margin is in the
       itwenty-first column, typing control-D at the start of a line will
       iput it back to the seventeenth column.  If the margin is presently
       iin the eighteenth or the twenty-fourth column, the effect would be
       ithe same.  But if the present margin is in the twenty-seventh or
       ithirtieth column, then a single control-D would set it back to
       icolumn twenty-five.
       i
       iOf course, you can reset the shiftwidth value via the :set command.
       iMany programmers reset that value to four. Then the stop points
       iwill be in every fourth column -- in column five, in column nine,
       iin column thirteen, in column seventeen, and so on. This reduces
       iline wrap in program source code with many levels of tab
       iindentation.
       i
       iHere's a visual representation of the difference: first of the
       idefault tab stops every eight columns, then as they are when reset
       ito every four columns:
       i
       i  +-------+-------+-------+-------+-...
       i  1       9      17      25      33
       i
       i  +---+---+---+---+---+---+---+---+-...
       i  1   5   9  13  17  21  25  29  33
       i
       iBut you just might be creating a problem by doing this.  With
       iidentical shiftwidth and tabstop values, backing up via a control-D
       irequires only erasing one tab character or erasing one or more
       ispace characters; never anything more complex.  With a shiftwidth
       ivalue of four and a tabstop value of eight, though, there will be
       itimes when a control-D requires the editor to remove one tab from
       ithe whitespace sequence with which it starts each line, and
       isimultaneously add four space characters.  A few versions of the
       ieditor cannot handle this complexity in some circumstances, and
       iwill at times put garbage in your file.  Even more likely is that
       ithe editor will mess up when it encounters tab characters in the
       imiddle of lines.
       i
       iThe tabstop option controls the number of spaces the editor thinks
       iyou want between tabstops.  With this option at its default value
       iof eight, there will be a tabstop every eight spaces, falling in
       ithe same columns as the shiftwidth stop points when that option's
       ivalue was also at its default value of eight.  So if you set the
       ivalues of both options to four, you will still have both options'
       istop points falling in the same columns, solving the problem posed
       iin the last paragraph.
       i
       iSolving it at quite a price, though.  The editor can use your
       ispecial value of four spaces between tabstops (or any other value
       iyou choose to give) when it is inserting and removing tabs as you
       itype, but it has no way to mark those characters in your file to
       isay "This is a four-column tab character" and "That is an
       ieight-column tab character". Not that there is any difference
       ibetween the tab characters themselves. A tab always moves the
       icursor to the next tabstop point in the line, wherever that may be.
       iThe difference is that some of your tabs will be inserted when you
       iexpected the editor to find a tabstop point every four columns;
       iothers when you (or someone else) were expecting tabstops every
       ieight columns.
       i
       iSo when you set your tabs value to four and then edit a file that
       iwas composed with tabs at their default value of eight,
       iindentations will be only about half as deep as the original writer
       iintended they should be. And when you write this file back to
       ipermanent storage, anyone who uses the file after you and has
       idefault tab settings will find the indentations you added to be
       iabout twice as deep as you intended -- this will often cause deeply
       iindented lines to be too long to be displayed on a single line of
       ithe user's screen or window.
       i
       iSince you've gotten this far in the tutorial, you're surely a
       iskilled user who can see how to get around this -- by writing a
       i.exrc file entry to translate eight-column-tab indentations into
       ifour-column-tab equivalents as you pull in a file to edit, and a
       imacro to do the reverse in the course of writing your work out to
       ipermanent storage.
       i
       iAn Exercise for You
       i
       iIt was several tutorial parts ago that I last put exercises for the
       ireader in the tutorial itself.  This seems like a good place to
       irevive that practice.  Just how would you write a command sequence
       ito handle that latter operation as regards start-of-line
       iindentations? Let's say you edit in screen mode, with your tabstop
       ioption set to a value of four, so that a ten-column indentation
       iconsists of two tabs followed by two spaces and a thirteen-column
       iindent is three tabs followed by one space.  But when you write the
       ifile to permanent storage, you want it to be in the conventional
       iformat of eight columns between tab points (at least for
       iindentations) -- so that same ten-column indentation will now
       iconsist of just one tab followed by two spaces, and the
       ithirteen-column indent will have a single tab followed by five
       ispaces -- to keep the indentations at the same depth they were.
       iWhat sequence of commands will accomplish this?
       i
       iTo simplify the problem, assume that the curly brace characters
       i("{" and "}") never appear in files you edit (if they are present,
       iwhich is common for program source code, choose another character
       ipair) and that you will only be writing to the original file name,
       ilet ^I stand for a real tab character when you write your answer,
       iand don't worry about how you would turn your command sequence into
       ia macro.  But, definitely do remember that you will be doing a
       iwrite in the middle of your editing session from time to time, to
       iguard against losing work in a system crash, so your command
       isequence must leave the file copy in the editor buffer just as it
       iwas before you wrote the modified version to storage, ready for you
       ito continue editing.
       i
       iThis exercise is not so difficult if you've been following this
       itutorial carefully.  The biggest hazard for those readers is that
       ithey may come up with a sequence that will work, but is much longer
       ithan it needs to be.  So if your solution seems long-winded, take a
       ilook at my hint before you jump to my solution.
       i
       iThese translator macros will work nicely for leading whitespace
       i(indentations), but it would take incredibly complex scripts
       i(whether Vi editor scripts or scripts for most other Unix
       iutilities) to deal with tabs in the interiors of lines.  The
       ipestilential problem there is that you don't know just where an
       iinterior tab character is placed -- how many positions in from the
       istart of the line.  For example, when you are trying to translate
       ieight-column tabs into four-column equivalents, and your macro
       ifinds a single eight-column tab in the middle of a line, is that
       itab in a column that is five or more columns from the next tab
       istopping point?  If yes, it must be replaced by two of the
       ifour-column tabs; if no, it is correct as it is.  Similarly, when
       igoing from four-column to eight-column tabs, a solitary tab in the
       imiddle of a line may be left there or may have to be replaced by
       ispace characters, depending on its column position.
       i
       iIf you must do this kind of translation, your best bets are the -e
       iand -i options to recent versions of the pr Unix command.  Running
       ia file through this utility will make the conversions correctly,
       ieven when the whitespace appears in the middle of lines.  The
       idownside is that your text may be reformatted to some degree.
       i
       iHard Tabs
       i
       iAnd then there is the hardtabs option to the :set command.  That
       ioption is used to tell the editor how far apart the tab stopping
       ipoints are on your physical terminal -- the editor uses this
       iinformation to decide what mix of tab and space characters will
       irepresent on your screen the indentation depth that's in your file.
       iThat is, the editor runs its own translator program, if necessary,
       ito make the spacings on your screen the same depth as those in your
       ifile.  Here too, any difference between this value and either of
       ithe previous two is likely to cause problems.  It's fortunate that
       iany value you give to this option will be overridden by the spacing
       ivalue that is in your Termcap or Terminfo file, because a
       idifference between the terminal tab setting Vi expects and that
       iwhich your terminal is actually using will scramble your screen for
       isure.
       i
       iSo my reluctant admonition to you is to leave all three of these
       ioptions set at their default values of eight.  Messing around with
       iany of them is just too likely to cause trouble.
       i
       iEnable and Disable autoindent
       i
       iOf course, all this means that when you have autoindentation on,
       ithe control-D, circumflex followed by control-D, and zero followed
       iby control-D sequences are all metastrings at the beginning of an
       iindented line.  To turn the metavalue off, so you can put one of
       ithese strings into the text at the start of an indented line, quote
       iin the control-D character by preceding it with a control-V.
       i
       iSo how do you turn the whole autoindent mode on and off? It's
       inormally off when you begin an editor session, and the usual way to
       iturn it on is to use the :set command.  Just type :se ai to turn
       ithis feature on.  When you want to tell the editor to stop
       iautomatically indenting every time you start a line with
       iwhitespace, type :se noai (from command mode) to turn autoindent
       ioff again.
       i
       iAutoindent also works with the line-mode append insert commands,
       iwhich can be abbreviated a i respectively.  These commands let you
       itype in new lines of text, below or above the current line,
       irespectively.  That is, they are generally the line-mode
       iequivalents of the screen-mode o O commands.  They can only be run
       iwhen you are in line mode; even preceding one of them with a colon
       i(":") will not let you run it from screen mode.
       i
       iThe setting of the autoindent option controls autoindentation
       iwithin these text insertions, too, but there is also another way to
       icontrol it that works only with these line-mode commands. Whenever
       iyou follow one of these commands or its abbreviation with an
       iexclamation point ("!"), without any characters or space in
       ibetween, you toggle the autoindention setting for that insertion
       ionly.  That is, if autoindentation was off, the ! turns it on
       iduring this insertion. Similarly, if autoindentation was on at the
       itime, the ! turns it off just for this insertion.
       i
       i[Editor's Note : Here's an example where it really helps to disable
       iautoindent.  When programming, I use a simple .exrc file containing
       ian se ai bf nu sw=4 ts=4 wm=0 line.  If I cut a section of indented
       ilines from one window and paste it into my program I get a
       istaircase effect as each line is inserted with one more tab than
       ithe last.  Most annoying.]
       i
 (DIR) Solutions
       i
       iNext Time
       i
       iThe next part of this tutorial will cover the :abbreviate and :map!
       icommands, both of which help you save typing while you are in
       itext-insertion submode.  Then, on to the editor's several
       ifacilities for creating macros and pseudo-macros that you can use
       ifrom the command submode.  And it will finish with more readers'
       iquestions and my answers, if you readers will send me some
       iworthwhile questions soon.
       i
       iYou may be laughing at that final word, "soon"
       i
       iBut my secret weapon this time is that, while my editor was away I
       ispent some time writing about half of the next part.  So, when she
       ireturns from a week of well-deserved vacation in mid-November, I
       iplan to have the completed tutorial installment waiting for her.
       iWish me luck.
       i
 (DIR) Part 9: Take Charge with Macros
 (DIR) Back to the index