Introduction
Vim's visual block mode (Ctrl+V) allows column-based text selection and editing. When files contain tabs, the visual block selection does not align with the visual column positions because tabs display as multiple screen columns but count as a single character:
``` File content (tabs shown as →): →→var x = 1; →var y = 2; var z = 3;
Visual block selection starts at wrong column because tab width differs from character count ```
Symptoms
- Block selection starts at unexpected column positions
- Inserting text in block mode shifts lines unevenly
- Block selection spans different columns on different lines
- Deleting a block of text produces misaligned results
- Works correctly on space-indented files but breaks on tab-indented files
Common Causes
- Mixed tabs and spaces in the file
tabstopsetting differs from the file's actual tab widthvirtualeditnot enabled, preventing cursor placement in virtual columns- File uses hard tabs but
expandtabis set in Vim - Screen column position differs from character position due to tab expansion
Step-by-Step Fix
- 1.Enable virtualedit for precise block mode positioning:
- 2.```vim
- 3." Allow cursor to move to any screen column
- 4.set virtualedit=block
- 5.
` - 6.This lets you position the block cursor at any visual column, even within tab characters.
- 7.Verify tab settings match the file:
- 8.```vim
- 9.:set tabstop? softtabstop? shiftwidth?
- 10.
` - 11.Ensure these match the file's indentation:
- 12.```vim
- 13.set tabstop=4
- 14.set softtabstop=4
- 15.set shiftwidth=4
- 16.
` - 17.Convert tabs to spaces for consistent block editing:
- 18.```vim
- 19." Convert all tabs to spaces in the current file
- 20.:set expandtab
- 21.:retab
- 22.
` - 23.This makes block selection align correctly because every character occupies exactly one column.
- 24.Detect and fix mixed indentation:
- 25.```vim
- 26." Show tabs as visible characters
- 27.:set list listchars=tab:»·,trail:·
" Find lines with mixed tabs and spaces /^\t* \+/ ```
- 1.Use block mode with virtualedit for precise editing:
- 2.
` - 3.1. Ctrl+V to start visual block mode
- 4.2. Move cursor to select the desired block
- 5.3. I (uppercase) to insert text at the start of the block
- 6.4. Type the text
- 7.5. Esc to apply to all lines
- 8.
`
Prevention
- Use
set expandtabin your.vimrcto convert tabs to spaces automatically - Configure EditorConfig (
.editorconfig) for consistent indentation across the team - Use
set listto visualize tabs and trailing whitespace - Run
:retabafter changing tab settings to normalize existing files - Add a pre-commit hook to check for mixed indentation
- Use
:set virtualedit=blockas a standard setting for developers who use block mode - For existing projects with tab indentation, match the project's
tabstopsetting - Document the team's indentation standard (spaces vs tabs, width) in CONTRIBUTING.md