What you may be used to in other editors is that there is a single behavior you set: tabs or N spaces?
This is not the case with Vim. Vim allows you to define at least three different behaviors that, as we'll see, can actually be mutually exclusive.
P.S. The following is an illustrated guide to the concepts behind tabs and indentation. If you're looking for the TL;DR, feel free to jump to the synopsis.
Here's a frame challenge: in each of the two lines below, where will the cursor go when you press the Tab key?
Try to remember how different programs will behave: not just your code editor, but different word processors as well, for example.
The answer:
The cursor, for each line, goes to the same column!
You may very well already know this intuitively. One thing you might gloss over, though, is that the Tab character has a different "length" in these two cases!
Hence, the frame challenge. When talking about tabs and spaces in programming, it's easy to fall into the trap of thinking about "tabs vs N spaces". The two aren't actually completely interchangeable!
The reality here is that Tab characters don't inherently have a length. What a Tab character actually does is bring the cursor forward to the next tab stop.
Tab stops can be thought of as markers ("stops") along the page, marking each multiple of a fixed width.
The typical word processor uses a fixed width of half an inch:
Terminals, and thus terminal-based editors, also have a concept of tab stops. The typical terminal uses a width of 8 character blocks, or 8 columns:
While these are the typical lengths of tab stops, most programs allow users to configure tab stop lengths themselves.
tabstop
tabstop
option is for: it configures the length of the tab stop.
With :set tabstop=4
, for example, tab stops will now mark every 4 columns along the line.
Notice that we haven't talked about indentation at all yet!
Tab stop length and indentation length can be mutually exclusive. In fact, in certain cases, the settings for both are indeed orthogonal.
Indentation length is configured separately in Vim with the shiftwidth
option.
This is used by Vim features that are expressly for indenting, such as:
>>
: Indent forward, to the right.
<<
: Indent backward, to the left.
=
: The indent operator, e.g. gg=G
to fix the whole file's indentation.
The Tab key is a special case — we'll get to that later.
While the shiftwidth
option tells Vim how many columns to indent a line, it doesn't actually tell Vim how.
As programmers well know, a 4-column indent can be created in two ways:
What governs this choice in Vim is the expandtab
option.
With :set expandtab
, Vim will use leading Space characters to fulfill the shiftwidth
indentation length.
With :set noexpandtab
, Vim will do its best to use Tab characters.
There's a minor caveat with :set noexpandtab
: if Vim cannot fit Tab characters into the indentation length (such as if shiftwidth
is indivisible by tabstop
), it uses a mix of Tab and Space characters.
The above example uses an indentation length of 6, but with tab stops of 4. The relevant settings would be:
set tabstop=4 shiftwidth=6 noexpandtab
In such a case, Vim indents with a leading Tab character and 2 Space characters.
As I've alluded to above, the Tab key (the key on your keyboard, not the character!) is a special case in Vim.
By default, the Tab key simply inserts a Tab character — no surprise there.
smarttab
optionHowever, Vim recognizes that it's popular among programmers to press the Tab key to perform indentation. In fact, it's likely this preconception that led you to some confusion with Vim's tab settings in the first place.
In light of this, Vim provides another option that can govern Tab key behavior: the smarttab
option.
With :set smarttab
, the Tab key becomes overloaded with two separate functions:
shiftwidth
.
expandtab
and softtabstop
options...except that's not the whole truth.
The expandtab
option actually governs Tab characters inserted by the Tab key as well!
With :set expandtab
, the Tab key will actually insert Space characters. For example, with
:set tabstop=8 expandtab
the Tab key will insert 8 Space characters.
But what if you want to configure this behavior separately from tabstop
? That is where the softtabstop
option comes in.
For example, with
:set tabstop=8 softtabstop=4 expandtab
the Tab key will insert 4 Space characters. But Tab characters (\x09
in ASCII) will visually display a tab stop length of 8 columns.
There are three distinct but interrelated behaviors regarding tab stops and indentation:
tabstop
shiftwidth
and expandtab
smarttab
, expandtab
, and softtabstop
4-column Tab indents.
set tabstop=4 shiftwidth=4 noexpandtab
tabstop=4
: Make tab stops 4 columns wide.
shiftwidth=4
: Indent 4 columns at a time.
noexpandtab
: Use Tab characters, not Space characters.
4-column Space indents.
set shiftwidth=4 expandtab
shiftwidth=4
: Indent 4 columns at a time.
expandtab
: Use Space characters, not Tab characters.
Popular with Python. In fact, this is automatically configured in the default ftplugin/python.vim
.
The tabstop
setting isn't actually needed to achieve 4-column Space indents per se — it's orthogonal.
2-column Space indents. Tab stops are 8 columns wide.
set tabstop=8 shiftwidth=2 expandtab
tabstop=8
: Make tab stops 8 columns wide.
shiftwidth=2
: Indent 2 columns at a time.
expandtab
: Use Space characters, not Tab characters.
This is my Vim setting of choice. 2-column Space indents are a norm in JavaScript code, so that's what I use for indentation.
Orthogonally, I use 8-column-wide tab stops because that's what a lot of terminal output optimizes for: mail clients, Git log viewers, etc.