created 2008 · complexity basic · author Metacosm · version 7.0
This tip explains how :retab converts tabs to spaces, or spaces to tabs, and provides a "super retab" command to convert only the whitespace used for indentation in programs.
Standard retab[]
You can set the 'expandtab' (abbreviated to 'et') option so each tab that you type is converted to an equivalent number of spaces. And you can use the :retab command to convert all existing tabs to spaces. You can do both in one command:
:set et|retab
You can also convert spaces to tabs:
:set noet|retab!
Both of the above examples should be used with caution. They convert all sequences, even those that might be in a "quoted string like this".
This tip shows how to convert only the indents at the left margin. Any spaces or tabs after the first non-white character are not affected.
Super retab[]
Use the following command to define a new SuperRetab command. You could enter this in Vim, or put it in your vimrc:
:command! -nargs=1 -range SuperRetab <line1>,<line2>s/\v%(^ *)@<= {<args>}/\t/g
For example, you may have a code snippet which uses two-space indents, and you want to entab the indents (convert each leading group of two spaces to a tab). To do this, visually select the code (press V then j), then enter:
:'<,'>SuperRetab 2
The above command would change:
for {
that;
}
to the following ("|-------" represents a tab):
|-------for {
|-------|-------that;
|-------}
The command :SuperRetab 5 would give the same result from the following selected text:
for {
that;
}
Alternative[]
An alternative super retab procedure is to use the following two commands:
:command! -range=% -nargs=0 Tab2Space execute '<line1>,<line2>s#^\t\+#\=repeat(" ", len(submatch(0))*' . &ts . ')'
:command! -range=% -nargs=0 Space2Tab execute '<line1>,<line2>s#^\( \{'.&ts.'\}\)\+#\=repeat("\t", len(submatch(0))/' . &ts . ')'
The above defines a Tab2Space and a Space2Tab command that convert leading whitespace (spaces and tabs that are not at the beginning of a line are not affected). These commands use the current 'tabstop' (abbreviated as 'ts') option.
Examples:
" Convert all leading spaces to tabs (default range is whole file): :Space2Tab " Convert lines 11 to 15 only (inclusive): :11,15Space2Tab " Convert last visually-selected lines: :'<,'>Space2Tab " Same, converting leading tabs to spaces: :'<,'>Tab2Space
Script[]
A more elaborate solution is to use the following script which provides these features:
- The commands allow an argument to specify the column width; if none is given, the
'tabstop'setting is used. - Redundant spaces in an indent are removed (in the above mapping, converting tabs to spaces will not change lines where there is a space before a tab in the indent).
- The search history is not changed (pressing
nwill do the same search it would have done before the conversion was performed). - The cursor position is restored, although the column will be slightly wrong owing to the different number of characters in the indent.
These commands are provided:
Space2Tab |
Convert spaces to tabs, only in indents. |
Tab2Space |
Convert tabs to spaces, only in indents. |
RetabIndent |
Execute Space2Tab (if 'expandtab' is set), or Tab2Space (otherwise).
|
Each command accepts an argument that specifies the number of spaces in a tab column. By default, the 'tabstop' setting is used.
" Return indent (all whitespace at start of a line), converted from
" tabs to spaces if what = 1, or from spaces to tabs otherwise.
" When converting to tabs, result has no redundant spaces.
function! Indenting(indent, what, cols)
let spccol = repeat(' ', a:cols)
let result = substitute(a:indent, spccol, '\t', 'g')
let result = substitute(result, ' \+\ze\t', '', 'g')
if a:what == 1
let result = substitute(result, '\t', spccol, 'g')
endif
return result
endfunction
" Convert whitespace used for indenting (before first non-whitespace).
" what = 0 (convert spaces to tabs), or 1 (convert tabs to spaces).
" cols = string with number of columns per tab, or empty to use 'tabstop'.
" The cursor position is restored, but the cursor will be in a different
" column when the number of characters in the indent of the line is changed.
function! IndentConvert(line1, line2, what, cols)
let savepos = getpos('.')
let cols = empty(a:cols) ? &tabstop : a:cols
execute a:line1 . ',' . a:line2 . 's/^\s\+/\=Indenting(submatch(0), a:what, cols)/e'
call histdel('search', -1)
call setpos('.', savepos)
endfunction
command! -nargs=? -range=% Space2Tab call IndentConvert(<line1>,<line2>,0,<q-args>)
command! -nargs=? -range=% Tab2Space call IndentConvert(<line1>,<line2>,1,<q-args>)
command! -nargs=? -range=% RetabIndent call IndentConvert(<line1>,<line2>,&et,<q-args>)
See also[]
- Converting tabs to spaces
- Highlight unwanted spaces
- Indent with tabs, align with spaces
- Indenting source code