Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reformat a source file to go from 2 space indentations to 3?

This question is nearly identical to this question except that I have to go to three spaces (company coding guidelines) rather than four and the accepted solution will only double the matched pattern. Here was my first attempt:

:%s/^\(\s\s\)\+/\1 /gc 

But this does not work because four spaces get replaced by three. So I think that what I need is some way to get the count of how many times the pattern matched "+" and use that number to create the other side of the substitution but I feel this functionality is probably not available in Vim's regex (Let me know if you think it might be possible).

I also tried doing the substitution manually by replacing the largest indents first and then the next smaller indent until I got it all converted but this was hard to keep track of the spaces:

:%s/^              \(\S\)/                     \1/gc

I could send it through Perl as it seems like Perl might have the ability to do it with its Extended Patterns. But I could not get it to work with my version of Perl. Here was my attempt with trying to count a's:

:%!perl -pe 'm<(?{ $cnt = 0 })(a(?{ local $cnt = $cnt + 1; }))*aaaa(?{ $res = $cnt })>x; print $res'

My last resort will be to write a Perl script to do the conversion but I was hoping for a more general solution in Vim so that I could reuse the idea to solve other issues in the future.

like image 951
stephenmm Avatar asked Jun 21 '11 16:06

stephenmm


2 Answers

Let vim do it for you?

:set sw=3<CR>
gg=G

The first command sets the shiftwidth option, which is how much you indent by. The second line says: go to the top of the file (gg), and reindent (=) until the end of the file (G).

Of course, this depends on vim having a good formatter for the language you're using. Something might get messed up if not.

Regexp way... Safer, but less understandable:

:%s#^\(\s\s\)\+#\=repeat(' ',strlen(submatch(0))*3/2)#g

(I had to do some experimentation.)

Two points:

  • If the replacement starts with \=, it is evaluated as an expression.
  • You can use many things instead of /, so / is available for division.
like image 158
Amadan Avatar answered Nov 03 '22 17:11

Amadan


The perl version you asked for...

From the command line (edits in-place, no backup):

bash$ perl -pi -e 's{^((?:  )+)}{"   " x (length($1)/2)}e' YOUR_FILE

(in-place, original backed up to "YOUR_FILE.bak"):

bash$ perl -pi.bak -e 's{^((?:  )+)}{"   " x (length($1)/2)}e' YOUR_FILE

From vim while editing YOUR_FILE:

:%!perl -pe 's{^((?:  )+)}{"   " x (length($1)/2)}e'

The regex matches the beginning of the line, followed by (the captured set of) one or more "two space" groups. The substitution pattern is a perl expression (hence the 'e' modifier) which counts the number of "two space" groups that were captured and creates a string of that same number of "three space" groups. If an "extra" space was present in the original it is preserved after the substitution. So if you had three spaces before, you'll have four after, five before will turn into seven after, etc.

like image 23
Brian Gerard Avatar answered Nov 03 '22 15:11

Brian Gerard