(Insert TipProposed template + minor manual clean) |
JohnBeckett (talk | contribs) m (Reverted edits by 58.194.224.124 (talk | block) to last version by JohnBot) |
||
(14 intermediate revisions by 7 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{TipNew |
||
− | {{TipProposed |
||
− | |id= |
+ | |id=1592 |
− | |previous= |
+ | |previous=1591 |
− | |next= |
+ | |next=1593 |
− | |created= |
+ | |created=2008 |
|complexity=basic |
|complexity=basic |
||
|author=Metacosm |
|author=Metacosm |
||
|version=7.0 |
|version=7.0 |
||
+ | |subpage=/200802 |
||
+ | |category1= |
||
+ | |category2= |
||
}} |
}} |
||
+ | This tip explains how <code>:retab</code> converts tabs to spaces, or spaces to tabs, and provides a "super retab" command to convert only the whitespace used for indentation in programs. |
||
− | ---- |
||
− | !!The Challenge |
||
− | The challenge is to write a function that redoes the tabbing only along the left side of the text. It is a ranged function that takes a single parameter which is the # of spaces used to represent a single indent in the file. |
||
+ | ==Standard retab== |
||
− | The differences between this and the standard retab are |
||
+ | You can set the '<code>expandtab</code>' (abbreviated to '<code>et</code>') option so each tab that you type is converted to an equivalent number of spaces. And you can use the <code>:retab</code> command to convert all existing tabs to spaces. You can do both in one command: |
||
− | # it takes a parameter for the number of spaces to equal a tab (doesn't use tabstop) |
||
⚫ | |||
− | # it only replaces groups of spaces at the start of a line. |
||
+ | :set et|retab |
||
⚫ | |||
+ | |||
+ | You can also convert spaces to tabs: |
||
+ | <pre> |
||
+ | :set noet|retab! |
||
+ | </pre> |
||
+ | |||
+ | 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 <code>SuperRetab</code> command. You could enter this in Vim, or put it in your [[vimrc]]: |
||
+ | <pre> |
||
⚫ | |||
+ | </pre> |
||
+ | |||
+ | 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 <code>V</code> then <code>j</code>), then enter: |
||
+ | <pre> |
||
+ | :'<,'>SuperRetab 2 |
||
+ | </pre> |
||
+ | The above command would change: |
||
− | So it could take a file that looks like |
||
<pre> |
<pre> |
||
for { |
for { |
||
Line 23: | Line 46: | ||
</pre> |
</pre> |
||
− | + | to the following ("<code>|-------</code>" represents a tab): |
|
− | |||
<pre> |
<pre> |
||
|-------for { |
|-------for { |
||
Line 31: | Line 53: | ||
</pre> |
</pre> |
||
+ | The command <code>:SuperRetab 5</code> would give the same result from the following selected text: |
||
− | and could create the same output from |
||
<pre> |
<pre> |
||
for { |
for { |
||
Line 37: | Line 59: | ||
} |
} |
||
</pre> |
</pre> |
||
− | via :call SuperRetab(5) |
||
− | ---- |
||
− | ---- |
||
+ | ==Alternative== |
||
− | p0g's attempt: (I think we have a winner here! --MetaCosm) |
||
+ | An alternative super retab procedure is to use the following two commands: |
||
<pre> |
<pre> |
||
+ | :command! -range=% -nargs=0 Tab2Space execute '<line1>,<line2>s#^\t\+#\=repeat(" ", len(submatch(0))*' . &ts . ')' |
||
− | function! SuperRetab(width) range |
||
+ | :command! -range=% -nargs=0 Space2Tab execute '<line1>,<line2>s#^\( \{'.&ts.'\}\)\+#\=repeat("\t", len(submatch(0))/' . &ts . ')' |
||
− | exe a:firstline . ',' . a:lastline . 's/\v%(^ *)@<= {'. a:width .'}/\t/g' |
||
⚫ | |||
− | OR as a command: |
||
⚫ | |||
</pre> |
</pre> |
||
+ | The above defines a <code>Tab2Space</code> and a <code>Space2Tab</code> 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 '<code>tabstop</code>' (abbreviated as '<code>ts</code>') option. |
||
− | Cleaned up function by FallingCow |
||
+ | Examples: |
||
− | _version 1_ |
||
<pre> |
<pre> |
||
+ | " Convert all leading spaces to tabs (default range is whole file): |
||
− | function! SuperRetab() range |
||
+ | :Space2Tab |
||
− | let x = 0 |
||
+ | " Convert lines 11 to 15 only (inclusive): |
||
− | while x < 10 |
||
+ | :11,15Space2Tab |
||
− | exe a:firstline . ',' . a:lastline . 's/^\(~[ ]*\)~[ ]\{' . &sw . '}/\1\t\2/e' |
||
+ | " Convert last visually-selected lines: |
||
− | let x = x + 1 |
||
+ | :'<,'>Space2Tab |
||
− | endwhile |
||
+ | " Same, converting leading tabs to spaces: |
||
− | endfunction |
||
+ | :'<,'>Tab2Space |
||
</pre> |
</pre> |
||
+ | ==Script== |
||
− | _version 2_ |
||
+ | 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 <code>'tabstop'</code> setting is used. |
||
− | function! SuperRetab(width) range |
||
+ | *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). |
||
− | let x = 0 |
||
+ | *The search history is not changed (pressing <code>n</code> will do the same search it would have done before the conversion was performed). |
||
− | while x < 10 |
||
+ | *The cursor position is restored, although the column will be slightly wrong owing to the different number of characters in the indent. |
||
− | exe a:firstline . ',' . a:lastline . 's/^\(~[ ]*\)~[ ]\{' . a:width . '}/\1\t\2/e' |
||
+ | |||
− | let x = x + 1 |
||
+ | These commands are provided: |
||
− | endwhile |
||
+ | {| class="cleartable" |
||
− | endfunction |
||
+ | | <code>Space2Tab</code> || Convert spaces to tabs, only in indents. |
||
⚫ | |||
+ | |- |
||
+ | | <code>Tab2Space</code> || Convert tabs to spaces, only in indents. |
||
+ | |- |
||
+ | | <code>RetabIndent</code> || Execute <code>Space2Tab</code> (if <code>'expandtab'</code> is set), or <code>Tab2Space</code> (otherwise). |
||
+ | |} |
||
+ | Each command accepts an argument that specifies the number of spaces in a tab column. By default, the <code>'tabstop'</code> setting is used. |
||
− | _version 3_ |
||
<pre> |
<pre> |
||
+ | " Return indent (all whitespace at start of a line), converted from |
||
− | function! SuperRetab(width) range |
||
+ | " tabs to spaces if what = 1, or from spaces to tabs otherwise. |
||
− | let @" = '' |
||
+ | " When converting to tabs, result has no redundant spaces. |
||
− | redir @" |
||
+ | function! Indenting(indent, what, cols) |
||
− | while @" !~~ 'E486:' |
||
+ | let spccol = repeat(' ', a:cols) |
||
− | silent! exe a:firstline . ',' . a:lastline . 'g/^\(~[ ]*\)~[ ]\{' . a:width . '}/s//\1\t\2/' |
||
+ | let result = substitute(a:indent, spccol, '\t', 'g') |
||
− | endwhile |
||
+ | let result = substitute(result, ' \+\ze\t', '', 'g') |
||
+ | if a:what == 1 |
||
+ | let result = substitute(result, '\t', spccol, 'g') |
||
+ | endif |
||
+ | return result |
||
endfunction |
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) |
||
⚫ | |||
+ | 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>) |
||
</pre> |
</pre> |
||
− | == |
+ | ==See also== |
+ | *[[Converting tabs to spaces]] |
||
+ | *[[Highlight unwanted spaces]] |
||
+ | *[[Indent with tabs, align with spaces]] |
||
+ | *[[Indenting source code]] |
||
+ | ==Comments== |
||
− | ---- |
Latest revision as of 12:30, 2 September 2012
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
n
will 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