Vim is very accommodating when it comes to tab Vs. space preferences. As I understand it, the
tabstop setting indicates the width of a tab character. The
shiftwidth setting specifies how many columns to increment/decrement when using the << and >> commands, whereas the
softtabstop setting influences the amount of whitespace to be inserted when you press the Tab key in insert mode. If
expandtab is on, the tab key inserts
softtabstop number of space characters. Whereas with
expandtab switched off, pressing the Tab key inserts a the smallest possible number of tab+space characters that matches
softtabstop. (Please correct me if I'm wrong.)
This final point makes me wonder: is there a practical case where you wouldn't want
shiftwidth == tabstop && tabstop == softtabstop? I can't think of one. As far as I am concerned, it would be most convenient if I could set all 3 of these to the same value, in one single assignment. e.g. calling:
which would be equivalent to running:
:set tabstop=4 softtabstop=4 shiftwidth=4
Can anyone suggest how this could be done?
Thanks for the replies so far from too much php, hobbs and kaiser.se. Rather than reply to each individually, I'm updating the question here.
Softtabstop with expandtab switched off
I said above that with expandtab switched off, pressing the Tab key inserts a the smallest possible number of tab+space characters that matches
softtabstop. I stand by that, but I think I need to explain what I meant. I shall attempt to do so by way of a few examples. To follow along, run
:set list so that you can see tab characters.
tabstop=4 softtabstop=2 shiftwidth=4 noexpandtab
In insert mode, pressing the tab key inserts 2 space characters. Press the tab key a second time, and instead of inserting two more space characters (for a total of 4 space characters) it replaces the previous 2 spaces with a single tab character. Tabstop is set to 4, so a single tab character has the same width as 4 spaces.
tabstop=4 softtabstop=6 shiftwidth=4 noexpandtab
In insert mode, pressing the tab key inserts 1 tab character plus 2 spaces. The tab character has a width of 4, so the total width is 6, and this is achieved using 3 characters. Pressing the tab key a second time inserts two tab characters, and removes the two spaces that were inserted previously. The total width is 12, and this is achieved using 3 characters.
In both of these examples, Vim inserts the minimum possible number of tab+space characters that matches softtabstop.
If I am working with expandtab switched off, I can't see myself wanting the extra granular control that can be achieved by setting softtabstop to a different value from tabstop. It would still be useful for me to be able to set
shiftwidth to the same value with a single command.
Does expandtab make softtabstop redundant?
tabstop=4 softtabstop=0 shiftwidth=4 expandtab
In insert mode, pressing the tab key inserts 4 spaces. Pressing the delete key deletes a single space - so you have to backspace 4 times if you hit the tab key by accident.
tabstop=4 softtabstop=4 shiftwidth=4 expandtab
In insert mode, pressing the tab key inserts 4 spaces. Pressing the backspace key deletes 4 spaces.
If I am working with
expandtab switched on, I would prefer the delete key to remove the same amount of whitespace as the tab key inserts. So in this case, too, I feel that it would be useful to be able to assign the same value to
A shortcut would still be useful
It's great that Vim provides so much flexibility, but I can't see myself needing it. I just want to be able to choose the width of a tab, and whether it is a 'hard' tab (using a tab character) or a 'soft' tab (made up of spaces). Toggling between hard and soft tabs is easy enough (
:set expandtab!), but I wish it was more straightforward to set the width of tab, without having to fiddle with 3 different parameters.
So my proposed suggestion for something like
:set stab=4 still sounds good to me.
stab option in Vim itself would not be easy, but I've whipped up this command/function that you can drop in your
.vimrc (or a plugin file if you're super-organized). Use
:Stab and you will be prompted for an indent level and whether or not to use
expandtab. If you hit enter without giving it a new indent level, it will just print the current settings.
" put all this in your .vimrc or a plugin file command! -nargs=* Stab call Stab() function! Stab() let l:tabstop = 1 * input('set shiftwidth=') if l:tabstop > 0 " do we want expandtab as well? let l:expandtab = confirm('set expandtab?', "&Yes\n&No\n&Cancel") if l:expandtab == 3 " abort? return endif let &l:sts = l:tabstop let &l:ts = l:tabstop let &l:sw = l:tabstop if l:expandtab == 1 setlocal expandtab else setlocal noexpandtab endif endif " show the selected options try echohl ModeMsg echon 'set tabstop=' echohl Question echon &l:ts echohl ModeMsg echon ' shiftwidth=' echohl Question echon &l:sw echohl ModeMsg echon ' sts=' echohl Question echon &l:sts . ' ' . (&l:et ? ' ' : 'no') echohl ModeMsg echon 'expandtab' finally echohl None endtry endfunction
Your understanding of
expandtab is wrong - so the
stab option you suggest wouldn't be very useful.
expandtab is for when you want to use spaces instead of tabs for everything. If you set
expandtab, then Vim ignores the
softtabstop option and uses
shiftwidth to work out how many spaces to insert.
softtabstop is only for when you would like to use a mix of tabs and spaces, allowing you to indent with fine control (2 or 4 spaces), while keeping tab width at a higher value (usually 8) so that text appears in the other applications. Setting
softtabstop=tabstop doesn't accomplish anything because Vim will always use tabs for indenting.
Update: As kaizer.se has pointed out, if you are using
expandtab, then you still need to set
softtabstop if you want Vim to backspace multiple spaces as though they are a tab.
expandtab is set then (as too much php points out),
softtabstop becomes redundant. The only reason you might set
shiftwidth differently from
tabstop would be to cater to an odd habit; for instance, you use four-space indents but you prefer tab to insert eight spaces.
expandtab is unset then things get fuzzier. If you want your code to look the same in with
cat and non-vim editors as it does in vim, then
tabstop should always be set at 8; in this case you would set
shiftwidth both to your preferred indent level. If you instead prefer that every "physical tab" in the file represents one indent level, you would set
shiftwidth to your preferred indent level and leave
softtabstop at zero (setting it equal to
tabstop is equivalent except that if you change
tabstop it will get out of sync, while zero just means "ignore this please").
This is my first attempt at writing VimScript, but here goes:
function! Stab(value) let &shiftwidth = a:value let &softtabstop = a:value let &tabstop = a:value endfunc
If I put this in my .vimrc file, I can call it by running
:call Stab(X), where X is the desired tab width. This is an adequate solution for now, but if anyone can suggest a way of making it easier to call I would be grateful.
I've also created a function that quickly summarizes the current settings, which I have mapped to ctrl-Tab:
nmap <C-Tab> :call TabParams()<CR> function! TabParams() echo "tabstop: ".&tabstop echo "shiftwidth: ".&shiftwidth echo "softtabstop: ".&softtabstop endfunc
Well, I put up a 100 point bounty for this answer, and now I've half solved it myself. Not sure if I can accept my own answer...
Are you changing your white space settings so often you really need a function to manage that? If you are messing with tabstop a lot and also setting expandtab, you are probably going to have a mess over time as you change files with different values passed to
stab. Today I use
:call stab (4), tomorrow it's
:call stab (2) and last week it was
:call stab (8). Sounds like even if you write it, you'll soon stop using it.
If you plan to always pass the same value to stab, why not just edit your global settings? In vim:
and add the following:
set tabstop=4 set shiftwidth=4 "tabs are 4 spaces wide (default = 8) set expandtab "Convert tabs to spaces
This is how my .vimrc is setup.
You can in edit mode also use Ctrl-T to indent and Ctrl-D to deindent to the next indentation level as set by
shiftwidth, regardless of the
expandtab settings. Vim will automatically add/remove spaces or tabs to bring you to the right column.
If you use these commands to control indentation instead of Tab/Backspace you don't have to worry about all these tab settings fitting together and always get to the correct indentation level.
One useful option is
softtabstop=-1 which will set it to the value of
You can also set
shiftwidth to 0, in which case the
tabstop value will be used.