439

Could someone explain to me in simple terms the easiest way to change the indentation behavior of Vim based on the file type? For instance, if I open a Python file it should indent with 2 spaces, but if I open a Powershell script it should use 4 spaces.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
EBGreen
  • 36,735
  • 12
  • 65
  • 85
  • 17
    BTW - PEP8 convention for Python says the tabstop should be 4 spaces and tabs should be 4 spaces. ref: http://stackoverflow.com/questions/120926/why-does-python-pep-8-strongly-recommend-spaces-over-tabs-for-indentation – cgseller May 03 '16 at 19:15

12 Answers12

349

You can add .vim files to be executed whenever vim switches to a particular filetype.

For example, I have a file ~/.vim/after/ftplugin/html.vim with this contents:

setlocal shiftwidth=2
setlocal tabstop=2

Which causes vim to use tabs with a width of 2 characters for indenting (the noexpandtab option is set globally elsewhere in my configuration).

This is described here: http://vimdoc.sourceforge.net/htmldoc/usr_05.html#05.4, scroll down to the section on filetype plugins.

SpoonMeiser
  • 19,918
  • 8
  • 50
  • 68
  • 248
    You should put that in `~/.vim/after/ftplugin/html.vim` instead. But as others have pointed out below, it’s much nicer to just add `autocmd FileType html setlocal shiftwidth=2 tabstop=2` to your `.vimrc`. – Aristotle Pagaltzis Oct 02 '08 at 20:38
  • 12
    Whoops, actually, that /is/ where I have that file. I'll fix the answer. I disagree though, I think separating out commands for different filetypes into separate files makes everything much easier, especially if you have requirements for many filetypes, or lots of options for some filetypes. – SpoonMeiser Oct 03 '08 at 10:20
  • 4
    Actually, there's not much reason to use the after directory for ftplugins. Vim will load all of them it finds in your runtimepath, not just the first like for syntax files. – graywh Jan 04 '09 at 21:00
  • 42
    FYI: don't use js for javascript filetype. Use javascript instead. (`autocmd FileType javascript setlocal shiftwidth=2 tabstop=2`) – Kiddo Jul 29 '13 at 03:37
  • 14
    You need to add `filetype plugin on` to your vimrc too. – gatoatigrado Jan 24 '14 at 21:06
  • 1
    for me putting the configuration file in ~/.vim/after/ftplugin folder did not work. Instead I put the file html.vim in ~/.vim/after/plugin folder and it worked. – vishal Jul 13 '18 at 15:44
  • How would I do it for typescript for example? – zardilior Jul 11 '19 at 19:19
  • 2
    @zardilior Use `typescript` file type. The file type of the currently opened file can be displayed by using `:set filetype?` command. – Peter Bašista May 12 '20 at 20:54
235

Use ftplugins or autocommands to set options.

ftplugin

In ~/.vim/ftplugin/python.vim:

setlocal shiftwidth=2 softtabstop=2 expandtab

And don't forget to turn them on in ~/.vimrc:

filetype plugin indent on

(:h ftplugin for more information)

autocommand

In ~/.vimrc:

autocmd FileType python setlocal shiftwidth=2 softtabstop=2 expandtab

I would also suggest learning the difference between tabstop and softtabstop. A lot of people don't know about softtabstop.

graywh
  • 9,640
  • 2
  • 29
  • 27
  • 1
    Thanks! Also thanks for that bit about 'ts' and 'sts'. Are there any particular pages that you'd recommend that discuss this difference and how to use it? – jvriesem Jul 23 '13 at 15:06
  • 12
    @jvriesem There's not much to it: 'ts' is how tab characters are displayed; 'sts' is how many "spaces" to insert when the tab key is pressed ; 'sw' is how many "spaces" to use per indent level; 'et' is whether to use spaces or tabs; 'sta' lets you insert 'sw' "spaces" when pressing tab at the beginning of a line. – graywh Jul 23 '13 at 17:28
  • 11
    I wonder if the full forms would be better to use, for clarity, rather than the curt sentence at the end. – icedwater Sep 28 '14 at 04:27
  • 23
    `sw` is short for `softwidth`, `sts` is short for `softtabstop`, `et` is short for `expandtab`, `setl` is short for `setlocal`, and `au` is short for `autocmd`. You can use the long forms instead of the short forms. – Flimm Jul 28 '15 at 12:57
  • 14
    I believe `sw` expands to `shiftwidth` rather than `softwidth`. – johncip Aug 22 '16 at 20:01
  • I asked and answered the question [What is the difference between `filetype plugin indent on` and `filetype indent on`?](https://vi.stackexchange.com/q/10124/7244) because of this post. – Flimm Jun 01 '17 at 11:02
  • Would give you +100 for the `filetype plugin indent on` - cause this explains how to switch smart indentations off and set your own. – toaster Apr 12 '22 at 15:40
106

edit your ~/.vimrc, and add different file types for different indents,e.g. I want html/rb indent for 2 spaces, and js/coffee files indent for 4 spaces:

" by default, the indent is 2 spaces. 
set shiftwidth=2
set softtabstop=2
set tabstop=2

" for html/rb files, 2 spaces
autocmd Filetype html setlocal ts=2 sw=2 expandtab
autocmd Filetype ruby setlocal ts=2 sw=2 expandtab

" for js/coffee/jade files, 4 spaces
autocmd Filetype javascript setlocal ts=4 sw=4 sts=0 expandtab
autocmd Filetype coffeescript setlocal ts=4 sw=4 sts=0 expandtab
autocmd Filetype jade setlocal ts=4 sw=4 sts=0 expandtab

refer to: Setting Vim whitespace preferences by filetype

ryche
  • 2,004
  • 2
  • 18
  • 27
Siwei
  • 19,858
  • 7
  • 75
  • 95
  • Comment for vimrc is single `"` :) –  Nov 03 '17 at 03:17
  • Yeah. My comment says use a single `"`, meaning don't close it with another `"`. Not sure why I commented that though. –  Mar 06 '19 at 10:10
63

Put autocmd commands based on the file suffix in your ~/.vimrc

autocmd BufRead,BufNewFile   *.c,*.h,*.java set noic cin noexpandtab
autocmd BufRead,BufNewFile   *.pl syntax on

The commands you're looking for are probably ts= and sw=

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • 21
    What's the advantage of this over by `FileType`? – Casey Chow Dec 17 '11 at 00:44
  • 5
    Is there any way to invert the match? – SystemParadox Feb 13 '12 at 12:33
  • 7
    I have had problems getting filetypes to work with html files (since the .html file isn't really HTML, but a template HTML file with a templating language). Filetypes doesn't seem recognize it as html, but this method will. – Mark Hildreth Jun 05 '13 at 20:38
  • 5
    @digitxp - the advantage is when your extension used doesn't match a defined "FileType". For example, in my installation, *.md means a filetype of Modula2 whereas I am using it for markdown. I could (a) change the default FileType settings (b) alter the filetype settings with a custom configuration or (c) quickly get what I want using this setting in my 1 .vimrc file I went with (c). – pdwalker Jul 09 '14 at 06:01
  • It would be worth pointing out that - assuming my quick read of the docs is correct - you can add multiple commands per filetype(s) this way, and they are guaranteed to be executed in the order given. – underscore_d Oct 20 '15 at 16:13
  • @MarkHildreth I had issues with vim ignoring the `html` `FileType` for Django template .html files, but fixed by using a `djangohtml` filetype. So to apply to css, html and Django templates, use something like: `autocmd FileType html,htmldjango,css setlocal shiftwidth=2 tabstop=2` – Jonny Nov 04 '16 at 13:43
28

I usually work with expandtab set, but that's bad for makefiles. I recently added:

:autocmd FileType make set noexpandtab

to the end of my .vimrc file and it recognizes Makefile, makefile, and *.mk as makefiles and does not expand tabs. Presumably, you can extend this.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • The better option is to enable :filetype plugins. The default one for Vim includes :setl noet, so you don't even need that aucmd in your vimrc. – graywh Jan 04 '09 at 20:57
  • 1
    OK. Can you explain the benefits of that, and what is involved in doing it? Why are filetype plugins better than autocmd? When should autocmd be used? Not used? – Jonathan Leffler Jan 06 '09 at 02:13
  • 5
    The filetype plugins that come with Vim will do helpful things like "setlocal noexpandtab" for makefiles, for example. Autocommands vs ftplugins for personal things like shiftwidth don't matter--it's just how you choose to structure your vim config. – graywh Apr 21 '09 at 17:57
20

Personally, I use these settings in .vimrc:

autocmd FileType python set tabstop=8|set shiftwidth=2|set expandtab
autocmd FileType ruby set tabstop=8|set shiftwidth=2|set expandtab
miken32
  • 42,008
  • 16
  • 111
  • 154
Nello
  • 225
  • 2
  • 2
  • 22
    Many languages have long established conventions, as do certain companies. Take NodeJS as an example of the former. Tabs should be two spaces. Headache, and quite silly, but important. – Paul Hazen Jun 18 '12 at 10:28
  • 3
    Why should tabs have to be the same for all circumstances? For a configuration file, 8 space tabs work fine, but for code with a lot of indents, 2 is much easier to manage. And then there are fixed conventions: node.js should have 2 space tabs, and python is actually syntactically invalid with anything other than 4 space tabs. – felixphew Aug 22 '15 at 21:28
  • 4
    @felixphew Python is perfectly correct with any number of spaces (or even tabs) as long as it stays the same the whole way through. – DJMcMayhem Mar 29 '16 at 22:37
  • @DJMcMayhem You're right - I should have said "strongly recommends". – felixphew Mar 31 '16 at 05:41
  • 1
    +1 to Nello. The tab character has a long established tradition of meaning a jump to the next position at a multiple of 8 chars. It is only because people wanted to use tab for "the next indent that looks good in my language" and because some text editors didn't bother making the difference between "adding a tab character" and "adding spaces for indenting", and people tweaked their editor to have it their way, that we now have this mess where tabs never display the intended way. Source code is text and the standard for text is 8-character tabs. – Florian F Oct 02 '16 at 16:35
  • How do I add for `C`. By default the shiftwidth is 3 even if I configure `set shiftwidth=4`. This works for other types but doesn't work for `C` – Ramana Reddy Oct 27 '17 at 07:14
7

This might be known by most of us, but anyway (I was puzzled my first time): Doing :set et (:set expandtabs) does not change the tabs already existing in the file, one has to do :retab. For example:

:set et
:retab

and the tabs in the file are replaced by enough spaces. To have tabs back simply do:

:set noet
:retab
Neysor
  • 3,893
  • 11
  • 34
  • 66
Juan Lanus
  • 2,293
  • 23
  • 18
5

Today, you could try editorconfig, there is also a vim plugin for it. With this, you are able not only change indentation size in vim, but in many other editors, keep consistent coding styles.

Below is a simple editorconfig, as you can see, the python files will have 4 spaces for indentation, and pug template files will only have 2.

# 4 space indentation for python files
[*.py]
indent_style = space
indent_size = 4

# 2 space indentation for pug templates
[*.pug]
indent_size = 2
chengbo
  • 5,789
  • 4
  • 27
  • 41
  • Does this override the tab settings set by user config or indent provided by runtime (or) other plugins? – Tun Dec 06 '21 at 04:31
5

For those using autocmd, it is a best practice to group those together. If a grouping is related to file-type detection, you might have something like this:

augroup filetype_c
    autocmd!
    :autocmd FileType c setlocal tabstop=2 shiftwidth=2 softtabstop=2 expandtab
    :autocmd FileType c nnoremap <buffer> <localleader>c I/*<space><esc><s-a><space>*/<esc>
augroup end

Groupings help keep the .vimrc organized especially once a filetype has multiple rules associated with it. In the above example, a comment shortcut specific to .c files is defined.

The initial call to autocmd! tells vim to delete any previously defined autocommands in said grouping. This will prevent duplicate definition if .vimrc is sourced again. See the :help augroup for more info.

67hz
  • 381
  • 3
  • 7
4

In Lua (for Neovim users) you can use RUNTIMEPATH/ftplugin/*yourfiletype*.lua with options like:

vim.opt_local.shiftwidth  = 2
vim.opt_local.tabstop     = 2

Just be sure to use string values in quotes. For example:

vim.opt_local.foldmethod  = 'marker'
Dzintars
  • 1,410
  • 21
  • 29
3

While you can configure Vim's indentation just fine using the indent plugin or manually using the settings, I recommend using a python script called Vindect that automatically sets the relevant settings for you when you open a python file. Use this tip to make using Vindect even more effective. When I first started editing python files created by others with various indentation styles (tab vs space and number of spaces), it was incredibly frustrating. But Vindect along with this indent file

Also recommend:

aymericbeaumet
  • 6,853
  • 2
  • 37
  • 50
haridsv
  • 9,065
  • 4
  • 62
  • 65
2

I use a utility that I wrote in C called autotab. It analyzes the first few thousand lines of a file which you load and determines values for the Vim parameters shiftwidth, tabstop and expandtab.

This is compiled using, for instance, gcc -O autotab.c -o autotab. Instructions for integrating with Vim are in the comment header at the top.

Autotab is fairly clever, but can get confused from time to time, in particular by that have been inconsistently maintained using different indentation styles.

If a file evidently uses tabs, or a combination of tabs and spaces, for indentation, Autotab will figure out what tab size is being used by considering factors like alignment of internal elements across successive lines, such as comments.

It works for a variety of programming languages, and is forgiving for "out of band" elements which do not obey indentation increments, such as C preprocessing directives, C statement labels, not to mention the obvious blank lines.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • nice! can i override it with an in-file hint? – Erik Aronesty Apr 13 '23 at 14:36
  • 1
    @ErikAronesty Looks like it. If a file has a `:vim ...` comment, that overrides the settings done with an autoload hook. Works for me. If you have any suggestions for autotab, let me know. I've been using it as-is for years, but I'm running into situations in which I would like the tabstop to be 4 not only the shiftwidth (in a file with expandtab on: no tabs). Autotab could use a command line argument for overriding the default. – Kaz Apr 14 '23 at 18:08