# Vim Tabs vs Spaces Configuration
Nothing causes more heated debates than tabs vs spaces, but what matters is consistency within a project. Vim has multiple settings that control indentation, and they interact in ways that can be confusing. Let me break down exactly how to configure Vim for your preferred style.
Understanding the Settings
Vim has several related settings:
| Setting | Purpose |
|---|---|
tabstop | Width of a tab character in spaces |
shiftwidth | Width for autoindent and <<, >> commands |
expandtab | Convert tabs to spaces when typing |
softtabstop | How many spaces a Tab key inserts/deletes |
smarttab | Use shiftwidth for Tab at line start |
Check current values:
:set tabstop? shiftwidth? expandtab? softtabstop?Tabs Configuration
Use actual tab characters:
set tabstop=4 " Tab character appears as 4 spaces
set shiftwidth=4 " Indentation uses 4 spaces
set noexpandtab " Don't convert tabs to spaces
set softtabstop=4 " Tab key inserts/deletes 4-space chunksWith these settings, pressing Tab inserts a real tab character that displays as 4 spaces.
Spaces Configuration
Use spaces instead of tabs:
set tabstop=4 " For displaying existing tabs
set shiftwidth=4 " Indentation width
set expandtab " Convert tabs to spaces
set softtabstop=4 " Tab key inserts 4 spacesWith expandtab, pressing Tab inserts spaces, not a tab character.
2-Space Indentation (Common for Web Development)
set tabstop=2
set shiftwidth=2
set expandtab
set softtabstop=2Detect Project Style Automatically
Use vim-sleuth or editorconfig for automatic detection:
Using vim-sleuth
Plug 'tpope/vim-sleuth'This plugin automatically adjusts indentation based on the file.
Using editorconfig
Install the plugin:
Plug 'editorconfig/editorconfig-vim'Create .editorconfig in your project:
```ini root = true
[*] indent_style = space indent_size = 4
[*.js] indent_size = 2
[*.py] indent_size = 4 indent_style = space
[Makefile] indent_style = tab ```
Convert Between Tabs and Spaces
Convert Tabs to Spaces
" Retab entire file (requires expandtab to be set)
:set expandtab
:retabThis converts all tabs to spaces using tabstop value.
Convert Spaces to Tabs
:set noexpandtab
:retab!The ! forces conversion even with noexpandtab.
Partial Conversion
Convert only leading whitespace:
" Replace leading spaces with tabs
:%s/^\s\+/\=repeat('\t', len(submatch(0))/&ts)/Filetype-Specific Indentation
Set different rules per file type:
```vim " Python: 4 spaces autocmd FileType python setlocal ts=4 sw=4 sts=4 expandtab
" JavaScript: 2 spaces autocmd FileType javascript setlocal ts=2 sw=2 sts=2 expandtab
" Go: tabs autocmd FileType go setlocal ts=4 sw=4 sts=4 noexpandtab
" Makefiles: tabs (required) autocmd FileType make setlocal ts=4 sw=4 sts=0 noexpandtab ```
Visual Indentation Guides
Show indentation levels visually:
Using Built-in List Chars
set list
set listchars=tab:▸\ ,trail:·,space:·This shows tabs as ▸ and trailing spaces as ·.
Using indent-blankline (Neovim)
require("ibl").setup()Using indentLine
Plug 'Yggdroot/indentLine'
let g:indentLine_char = '│'Preserve Existing Indentation
Don't change indentation when opening files:
set preserveindentSmart Tab Handling
Behave intelligently at line start:
set smarttabWith smarttab, Tab at the beginning of a line inserts shiftwidth spaces, not tabstop.
Show Current Settings
Create a command to display indentation info:
command! IndentSettings echo 'tabstop='.&ts.' shiftwidth='.&sw.' expandtab='.&et.' softtabstop='.&stsUse :IndentSettings to see current values.
Fix Misaligned Indentation
Reindent Entire File
gg=GThis reindents from first line to last using syntax rules.
Fix Specific Range
" Reindent lines 10-20
:10,20normal! ==Copy Indentation from Another File
```vim " Open another file :split template.py
" Copy settings :setlocal ts=<value from other file> :setlocal sw=<value from other file> :setlocal sts=<value from other file> :setlocal et=<value from other file> ```
Common Issues
Mixed Tabs and Spaces
When a file has both:
```vim " Visualize :set list
" Retab to normalize :set expandtab :retab ```
Backspace Deletes Wrong Amount
If backspace deletes too many or too few spaces:
```vim " Ensure softtabstop matches your intent set softtabstop=4
" And enable proper backspace behavior set backspace=indent,eol,start ```
Autoindent Wrong Size
If autoindent uses wrong width:
set shiftwidth=4
set autoindent
set smartindentOr for smarter indentation:
filetype plugin indent onCopy-Paste Messes Up Indentation
Use paste mode:
:set paste
" Paste your content
:set nopasteOr use "+p to paste from system clipboard without reindentation.
Makefile Requirement
Makefiles require tabs. Ensure they're preserved:
autocmd FileType make setlocal noexpandtabComplete Indentation Setup
Here's a practical .vimrc configuration:
```vim " Default to 4-space indentation set tabstop=4 set shiftwidth=4 set softtabstop=4 set expandtab set autoindent set smartindent set smarttab
" Filetype-specific overrides augroup IndentationSettings autocmd! autocmd FileType python,javascript,typescript,json,html,css setlocal ts=2 sw=2 sts=2 autocmd FileType go,rust setlocal ts=4 sw=4 sts=4 noexpandtab autocmd FileType make setlocal ts=4 sw=4 noexpandtab augroup END
" Visual indication set list listchars=tab:▸\ ,trail:·
" Toggle paste mode set pastetoggle=<F2> ```
Quick Reference
```vim " Show current settings :set ts? sw? et? sts?
" Tabs: use tab characters :set ts=4 sw=4 sts=4 noet
" Spaces: use spaces :set ts=4 sw=4 sts=4 et
" Convert file to spaces :set et | :retab
" Convert file to tabs :set noet | :retab! ```
With these settings and commands, you can handle any indentation style requirement.