Is there a way to force vim to use tabs to do the initial indent, but when running the retab! command NOT replace inner word spacing with tabs?
问题:
回答1:
In my experience the best way to do this is with a custom function:
" Retab spaced file, but only indentation
command! RetabIndents call RetabIndents()
" Retab spaced file, but only indentation
func! RetabIndents()
let saved_view = winsaveview()
execute '%s@^\( \{'.&ts.'}\)\+@\=repeat("\t", len(submatch(0))/'.&ts.')@'
call winrestview(saved_view)
endfunc
You can then use:
:RetabIndents
to replace all leading spaces as tabs but not to affect tabs after other characters. It assumes that 'ts' is set correctly. You can go a long way to making files that are misaligned better by doing something like this:
:set ts=8 " Or whatever makes the file looks like right
:set et " Switch to 'space mode'
:retab " This makes everything spaces
:set noet " Switch back to 'tab mode'
:RetabIndents " Change indentation (not alignment) to tabs
:set ts=4 " Or whatever your coding convention says it should be
You'll end up with a file where all the leading whitespace is tabs so people can look at it in whatever format they want, but where all the trailing whitespace is spaces so that all the end-of-line comments, tables etc line up properly with any tab width.
Edit
Explanation of the 'exe' line:
execute '%s@^\( \{'.&ts.'}\)\+@\=repeat("\t", len(submatch(0))/'.&ts.')@'
" Execute the result of joining a few strings together:
%s " Search and replace over the whole file
@....@....@ " Delimiters for search and replace
^ " Start of line
\(...\) " Match group
\{...} " Match a space the number of times in the curly braces
&ts " The current value of 'tabstop' option, so:
" 'string'.&ts.'string' becomes 'string4string' if tabstop is 4
" Thus the bracket bit becomes \( \{4}\)
\+ " Match one or more of the groups of 'tabstop' spaces (so if
" tabstop is 4, match 4, 8, 12, 16 etc spaces
@ " The middle delimiter
\= " Replace with the result of an expression:
repeat(s,c) " Make a string that is c copies of s, so repeat('xy',4) is 'xyxyxyxy'
"\t" " String consisting of a single tab character
submatch(0) " String that was matched by the first part (a number of multiples
" of tabstop spaces)
len(submatch(0)) " The length of the match
/'.&ts.' " This adds the string "/4" onto the expression (if tabstop is 4),
" resulting in len(submatch(0))/4 which gives the number of tabs that
" the line has been indented by
) " The end of the repeat() function call
@ " End delimiter
回答2:
From my answer to this other (*) question:
To settle this little problem I recomend a search, instead of retab.
:%s/^\(^I*\)␣␣␣␣/\1^I/g
This search will look in the whole file for any lines starting with whatever number of tabs, followed by 4 spaces, and substitute it for whatever number of tabs it found plus one.
Than you need to redo the search with @:
or 10@:
Its better explained in the link bellow.
(*) How can I convert spaces to tabs in Vim or Linux?