Change 2-space indent to 4-space in vim
VimVim Problem Overview
I've some codes copied from the Internet that have 2-space indenting and I want to change it into 4-space indenting. I wonder if there is a short vim routine to accomplish the task without having to write vim script? Here is how I'm currently doing it with an HTML file:
- Record a macro
- Go to the beginning of a line
- Visual select all whitespaces until the first occurrence of "<"
- Yank and paste all whitespaces (basically to double them)
- Replay the macro till the end of the file
In short qa0vt<yp<esc>jq
Pitfalls:
The macro fails for a blank line or a line that doesn't start with "<". And I have no idea how to extend this solution to non-HTML file.
Vim Solutions
Solution 1 - Vim
A general way of changing the indent is by changing the tabstop:
Paste your file into an empty buffer, then:
:set ts=2 sts=2 noet
:retab!
This changes every 2 spaces to a TAB character, then:
:set ts=4 sts=4 et
:retab
This changes every TAB to 4 spaces.
The advantage of this method is that you can also use it the other way around, to convert from 4 to 2 spaces for example.
Solution 2 - Vim
It may be possible with :set shiftwidth=4
and gg=G
.
Solution 3 - Vim
What I do is very similar to esneider and cforbish's approaches, but a bit quicker to type:
:%s/^\s*/&&
Simply replaces leading space (spaces or tabs) with twice as much leading space (&
is substituted with the matched expression).
Solution 4 - Vim
This is a very old question, however all the answers are ... wrong ... Vim has a very easy way to reindent the entire file. I learned this after writing my own function to do it, so I'm in the same ignorance boat ;)
type
gg=G
this is assuming that you have your tabstop set to what you like, (so for the OP it would be ts=4)
I learned this from http://vim.wikia.com/wiki/Fix_indentation , which mentions
> In normal mode, typing gg=G will reindent the entire file. This is a special case; = is an operator. Just like d or y, it will act on any text that you move over with a cursor motion command. In this case, gg positions the cursor on the first line, then =G re-indents from the current cursor position to the end of the buffer.
Solution 5 - Vim
I used this regular expression (it doubles the number of leading spaces):
%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
Solution 6 - Vim
Similar (but somewhat simpler) to cforbish's answer, this regex will duplicate the leading spaces
:%s/^\( \+\)/\1\1
Or you can use this other regex to transform 2-spaces into 4-spaces, preserving single spaces (and odd amounts in general)
:%s/^\(\( \)\+\)/\1\1
That is,
- 1 space ⇢ 1 space
- 2 spaces ⇢ 4 spaces
- 3 spaces ⇢ 5 spaces
- 4 spaces ⇢ 8 spaces
Solution 7 - Vim
In addition to @spro's answer, I put this in my .vimrc
command! -range=% Format :<line1>,<line2>s/^\s*/&&
Just type :Format
.
With visual selection, this only formats the selected lines.
Without visual selection, this formats the whole file.
Solution 8 - Vim
This is a variant of the regex based answers.
I have a bash script in my local bin directory that will double the amount of whitespace at the start of a line. Input can be stdin or a file:
$ cat ~/bin/dblsp
#!/bin/bash
file=${1--}
while IFS= read -r line; do
echo "$line" | sed 's/\s*/&&/'
done < <(cat -- "$file")
I use this within vim by visually selecting a line and issuing the following command:
:'<,'>!dblsp
This saves me the need to type (or remember) the regex.
I also use it in maps like the following:
nnoremap <leader>] `[V`]!dblsp<CR>
which will apply it to a block of recently pasted text. I usually use the following map to paste rather than :set paste
nnoremap <leader>p :r !xclip -o<CR>
My usual workflow is:
- select code snippet (eg the example code on this page is 2 spaces but I want 4)
- paste code snippet (,p)
- change spacing (,])
or simply changing the indent on yanked blocks pasted from another buffer.