Monday, August 20, 2018

Nice Vim trick for Python code

By Vasudev Ram

Here's a Vim editing trick which can be useful for indenting Python code (in some situations):

Let's say I have this program, p1bad.py:
$ type p1bad.py

def foo(args):
print "in foo"
def bar():
print "in bar"
Running it gives:

$ python p1bad.py
File "p1bad.py", line 3
print "in foo"
^
IndentationError: expected an indented block
The indentation is incorrect; the first print statement should be indented one level under the "def foo" line, and the second one should be similarly indented under the "def bar" line.

Imagine that the incorrect indentation was due to fast typing, or was done by a beginner. We can fix this by opening the file in vim and typing this vim command (with the cursor being anywhere in the file):

    gg=G

How does it work?

The gg moves the cursor to the first line of the file.

Then, the = means indent some text. What text? The text that would have been moved over by the following cursor movement. And the next movement command is G (which is short for $G). That means move to the last line of the file, since $ means the last line, and G means move to a specified line (in this context).

So the net result is that the part of the file that would have been moved over (in the absence of the = part of the command), gets indented instead. In this case, it is the whole file, since we were at the top and said to move to the bottom.

Then I save the file as p1good.py. The result is:
$ type p1good.py

def foo(args):
    print "in foo"
def bar():
    print "in bar"
We can see that the code is now correctly indented.

Another example, p2bad.py:
$ type p2bad.py

def foo(args):
print "in foo"
    def bar():
    print "in bar"
Here, the user has again not indented the two print statements correctly. Note that in this case, function bar is nested under function foo (which is okay, since nested functions are allowed in Python).

Running p2bad.py gives:
$ python p2bad.py
File "p2bad.py", line 3
print "in foo"
^
IndentationError: expected an indented block
We get the same error.

If we now type the same command, gg=G, and save the file as p2good.py, we get:
$ type t2good.py

def foo(args):
    print "in foo"
    def bar():
        print "in bar"
Again, the indentation has been corrected.

If we were already at the start of the file, we could just type:

    =G

Note that this technique may not work in all cases. For example, in the case of p2bad.py above, the user may not have meant to nest function bar under function foo. They may have meant it to be a non-nested function, indented at the same level as foo. And vim may not be able to determine the intention of the user, in this and some other cases.

So use the technique with care, and preferably make a backup copy of your file before changing it with this technique.


If you're new to vi/vim, and want to learn its basics fast, check out my vi quickstart tutorial on Gumroad. It's short, so you can read it and get going with vi/vim in half an hour or less.

- Enjoy.

- Vasudev Ram - Online Python training and consulting

Get updates (via Gumroad) on my forthcoming apps and content.

Jump to posts: Python * DLang * xtopdf

Subscribe to my blog by email

My ActiveState Code recipes

Follow me on: LinkedIn * Twitter

Are you a blogger with some traffic? Get Convertkit:

Email marketing for professional bloggers



1 comment:

Vasudev Ram said...

Typo:

This part of the post:

>If we now type the same command, gg=G, and save the file as p2good.py, we get:

>$ type t2good.py

should read as follows:

>If we now type the same command, gg=G, and save the file as p2good.py, we get:

>$ type p2good.py

I originally had created all the example files with names starting with "t" (for "temporary"), and then later while editing the post, changed them all to start with "p" (for "program"), and then did make a couple of passes through the post to make the corresponding changes in the filenames, but somehow missed this one.