1

I want to configure Vim to use spaces for <Tab>s everywhere. Therefore, I've had a look at :h tabstop to figure out how to perform the configuration.

Looking at the help text, option 2. seems appropriate for my use case. However, it doesn't mention softtabstop, why not? Without setting softtabstop, every <Tab> I insert result in the default number of spaces for the filetype (4 for Python), and not the value configured for tabstop?

Shouldn't softtabstop be set when using option 2? If not, then indentation and <Tab>s inserted in Insert mode results in different number of spaces, which is awkward.

Bonus: What is the standard way of handling <Tab>s in Vim that most users opt for?

Bonus: what is meant by "Then Vim will use a mix of tabs and spaces, but typing <Tab> and <BS> will behave like a tab appears every 4 (or 3) characters." in option 1?

:h tabstop:

Number of spaces that a <Tab> in the file counts for.  Also see
|:retab| command, and 'softtabstop' option.

Note: Setting 'tabstop' to any other value than 8 can make your file
appear wrong in many places (e.g., when printing it).

There are four main ways to use tabs in Vim:
1. Always keep 'tabstop' at 8, set 'softtabstop' and 'shiftwidth' to 4
   (or 3 or whatever you prefer) and use 'noexpandtab'.  Then Vim
   will use a mix of tabs and spaces, but typing <Tab> and <BS> will
   behave like a tab appears every 4 (or 3) characters.
2. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use
   'expandtab'.  This way you will always insert spaces.  The
   formatting will never be messed up when 'tabstop' is changed.
3. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use a
   |modeline| to set these values when editing the file again.  Only
   works when using Vim to edit the file.
4. Always set 'tabstop' and 'shiftwidth' to the same value, and
   'noexpandtab'.  This should then work (for initial indents only)
   for any tabstop setting that people use.  It might be nice to have
   tabs after the first non-blank inserted as spaces if you do this
   though.  Otherwise aligned comments will be wrong when 'tabstop' is
   changed.
  • Anedocte: That is the correct way to do. But the best way is to simply blindly set values and stick to the permutation that happens to work out :) – Quasímodo Oct 17 at 11:34
1

However, it doesn't mention softtabstop, why not?

I suppose it's because softtabstop can be set up independently.

Without setting softtabstop, every Tab I insert result in the default number of spaces for the filetype (4 for Python), and not the value configured for tabstop?

Actually it's vice versa. If you miss it, maybe it's because of Python's ftplugin who had already set softtabstop=4 for you.

If not, then indentation and Tabs inserted in Insert mode results in a different number of spaces, which is awkward.

If one has set smarttab then tab is forced to shiftwidth at line beginning, so the argument does not apply. However, smarttab is neither set by default nor mentioned there. So maybe we should blame Bram (or whoever wrote this topic) on this point.

what is meant by "Then Vim will use a mix of tabs and spaces, but typing and will behave like a tab appears every 4 (or 3) characters."

Obviously, if one has set noexpandtab, while softtabstop is less than tabstop, then hitting tab several times may result in a full tabstop (or more). At that point Vim will "optimize" whitespace by inserting hard tabs as expected.

What is the standard way of handling Tabs in Vim that most users opt for?

I don't know anything about "standards". I can only speak for myself. So what I have is

set tabstop& expandtab smarttab softtabstop=-1 shiftround shiftwidth=4

In principle, setting both softtabstop and smarttab is redundant yet it doesn't do any harm.

| improve this answer | |
  • What exactly is the difference between tabstop and softtabsstop? Does tabstop define how many spaces a TAB accounts for, while softtabstop define how many spaces a TAB accounts for while performing editing in Insert mode, so that if softtabstop is greater than tabstop, then softtabstop / tabstop TABs are inserted and spaces for the rest, if noexpandtab? Where as softtabspaces spaces are inserted, if expandtab? – Shuzheng Oct 17 at 16:58
  • @Shuzheng Roughly speaking, tabstop is "space"-equivalent of every byte(9) from buffer; while softtabstop is "space"-equivalent of "tab" key hit. – Matt Oct 17 at 17:15
  • @Shuzheng Of course, also rounding needs to be applied, so exact value is calculated dynamically. – Matt Oct 17 at 17:17
  • What does set tabstop& mean? I would normally use & for something like :echo &shiftwidth. – Shuzheng Oct 18 at 10:48
  • @Shuzheng This is to reset to default value. Please, read :h :set if you still miss some syntax bits. – Matt Oct 18 at 11:09
1

I'm going to off an alternative perspective for forcing spaces everywhere: leave tabstop alone unless you're viewing files with tabs and you want them to be skinnier to save on screen real-estate. (So, leave it as default, 8.) This is more realistic, though in general one cannot control how tabs appear in foreign environments.

Set expandtab, of course (note that in some filetypes, it should not be set! make, for example. The default ftplugin does this already, so that works out.)

Then, set locally shiftwidth and softtabstop for filetypes you need to change the indent settings. A quick git-grep in my Dotfiles shows some examples:

links/vim/after/ftplugin/applescript.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/css.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/gitcommit.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/gitconfig.vim:8:20:setlocal tabstop=8 shiftwidth=8 softtabstop=8
links/vim/after/ftplugin/go.vim:10:10:setlocal shiftwidth=0
links/vim/after/ftplugin/html.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/java.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/javascript.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/make.vim:6:10:setlocal shiftwidth=8
links/vim/after/ftplugin/matlab.vim:8:10:setlocal shiftwidth=4 softtabstop=4
links/vim/after/ftplugin/ruby.vim:13:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/scala.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/scss.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/sh.vim:8:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/sml.vim:8:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/typescript.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/verilog.vim:6:10:setlocal shiftwidth=4 softtabstop=4
links/vim/after/ftplugin/vim.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/xml.vim:5:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/yaml.vim:6:10:setlocal shiftwidth=2 softtabstop=2
links/vim/after/ftplugin/zsh.vim:8:10:setlocal shiftwidth=2 softtabstop=2

Note that I had to set shiftwidth back to 8 in makefiles (the ftplugin also sets sofftabstop to 0) and both to 0 in go files.

I do set shiftround so that > and < behave like I want. i_CTRL-T and i_CTRL-D always round to a multiple of shiftwidth, so this unifies them.


However, it doesn't mention softtabstop, why not?

Sure it does, just not directly next to option 2:

Also see |:retab| command, and 'softtabstop' option.

Bonus: what is meant by "Then Vim will use a mix of tabs and spaces, but typing and will behave like a tab appears every 4 (or 3) characters." in option 1?

As Matt mentions, certain combinations of indents may not align directly with tab-boundaries. Vim will use tabs where it can and then fill in spaces so the visual indent matches what would be there. Personally I find this a bit terrible, since (as noted) you cannot control how wide tabs are outside of your own environment. This means that using tabs to align code is liable to break when other people are viewing it. Spaces don't suffer from that.


More information in an excellent screencast: Vimcasts: tabs and spaces

| improve this answer | |
  • Thank you, Ben. So, you opt partially for option 1, namely setting shiftwidth and softtabstop; however, you set expandtab, while option 1 opt for noexpandtab, why? – Shuzheng Oct 17 at 17:10
  • Can you confirm the following: tabstop is used to define the width of a TAB in spaces; softtabstop is used to define the width of TABs in Insert mode, in which case softtabstop / tabstop TABs are inserted and spaces for the rest, if noexpandtab, or softtabstop spaces are inserted, if expandtab? – Shuzheng Oct 17 at 17:13
  • If expandtab, then tabstop only really applies to viewing (external) files with TABs? – Shuzheng Oct 17 at 17:15
  • re expandtab, I want spaces. tabstop defines how wide a Tab character appears (in spaces). softtabstop is what is used when pressing <tab>, <bs>, etc. Yes, with expandtab, tabstop only matters when the files have tabs (e.g., go, make, other people's files). See :help for each of the options for a more detailed description of what they do – D. Ben Knoble Oct 17 at 17:43
  • Thanks, <bs> is for back-space (delete)? Why is that related to <tab>? – Shuzheng Oct 17 at 18:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.