ChatGPT解决这个技术问题 Extra ChatGPT

Changing Vim indentation behavior by file type

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.

BTW - PEP8 convention for Python says the tabstop should be 4 spaces and tabs should be 4 spaces. ref: stackoverflow.com/questions/120926/…

S
SpoonMeiser

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.


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.
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.
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.
FYI: don't use js for javascript filetype. Use javascript instead. (autocmd FileType javascript setlocal shiftwidth=2 tabstop=2)
You need to add filetype plugin on to your vimrc too.
g
graywh

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.


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 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.
I wonder if the full forms would be better to use, for clarity, rather than the curt sentence at the end.
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.
I believe sw expands to shiftwidth rather than softwidth.
r
ryche

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


Comment for vimrc is single " :)
Yeah. My comment says use a single ", meaning don't close it with another ". Not sure why I commented that though.
P
Paul Tomblin

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=


What's the advantage of this over by FileType?
Is there any way to invert the match?
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.
@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).
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.
J
Jonathan Leffler

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.


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.
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?
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.
m
miken32

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

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.
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 Python is perfectly correct with any number of spaces (or even tabs) as long as it stays the same the whole way through.
@DJMcMayhem You're right - I should have said "strongly recommends".
+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.
N
Neysor

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

6
67hz

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.


c
chengbo

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

Does this override the tab settings set by user config or indent provided by runtime (or) other plugins?
a
aymericbeaumet

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:

pythonhelper

python_match

python_ifold


D
Dzintars

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'

K
Kaz

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.