Convert entire (Python) file from 2-space indent to 4-space indent

Question:

I regularly work with Python files that are provided to me as templates, which use an indentation of 2. However, I personally prefer working with an indentation width of 4, which is what I’ve set in my .vimrc. However, because of the indentation-sensitivity of Python, the typical gg=G way to fix indentation to my preferred indentation width does not work well at all to convert a file to my preferred indentation. Furthermore, just leaving the indentation at a width of 2 screws up with my tabstop settings.

To fix this, what I’d like to do is have some system to convert a 2-space indented file into a 4-space indented file. I don’t know what the easiest way to do this would be, but I’m thinking to vmap <Tab> to increase the tab width of the selected lines by 1, and vmap <S-Tab> to decrease the width by 1. I don’t know if there is some built-in method to do this, or if this would require some find/replace rule, but I think having some way to fix the indentation to my preferred width would be useful, given that the autoindent is not smart enough to fix this properly.

Asked By: Joeytje50

||

Answers:

Since you have spaces (instead of tabs) as the indent, it seems like you just need to double the number of leading spaces on each line.

You can use ggVG to select your entire file. Pressing : will enter some defaults, from there you can add s/^(s*)/11 to double leading spaces in the line.

Explanation of the regex: ^ indicates the beginning of a line. (s*) is a capture group containing any number of spaces. 1 refers to that capture group, and 11 means to repeat that group twice.

TL;DR: ggVG=:s/^(s*)/11

Answered By: Josh Brunton

reindent.py

There is a similar post that deals with this issue.

(From that post) You can use reindent.py, a script provided with your python installation to change python files to use 4-space indents and no hard tab characters.

You can invoke it using

python3 -m reindent

(You can even run it without the python3 -m)

And use the help flag for a list of possible flags

python3 -m reindent --help

Install it using pip (pip install reindent) if it doesn’t exist in your system by default.

Use within vim

From this answer by Chris. You can actually use reindent.py within vim:

:%! reindent

From the command line it can be used to reindent multiple files (eg all files in a directory, or even recursively down a directory tree).

Answered By: laughingclouds

In vim:

" Convert 2-spaces indent to tabs
:set noexpandtab tabstop=2
:retab!

" Convert tabs to 4-spaces indent
:set expandtab tabstop=4
:retab
Answered By: phd

Based on the answer given by phd, I decided to tweak it a bit and write a script that automatically fixes the tab width based on pressing 2<Tab> for going from 2 to 4 tabs, as well as being able to fix intermingled tab/4-space indentation by pressing 4<Tab. It makes use of a global variable to prevent the command from running multiple times, but otherwise simply executes the commands given in phd’s answer. Pressing a number key and then Tab in normal mode will cause the indentation to be changed from that number to your default tabstop setting.

let g:retab_done = 0
function Retab()
    if !v:count || g:retab_done
        return
    endif
    let g:retab_done = 1
    let current_width = &tabstop
    execute "set noexpandtab tabstop=" . v:count
    retab!
    execute "set expandtab tabstop=" . current_width
    retab
    return
endfunction
nmap <Tab> :call Retab()<CR>
Answered By: Joeytje50