Josh Katofsky Josh Katofsky - 2 months ago 45
CoffeeScript Question

Atom auto indentation script ruins Python indentation

I wrote this function in the init.coffee file for my Atom config to auto indent an entire file:

atom.commands.add 'body', 'custom:auto-format', ->
editor = atom.workspace.getActiveTextEditor();

oldSelection = editor.getSelectedBufferRanges();

editor.selectAll();
editor.autoIndentSelectedRows();

editor.setSelectedBufferRanges(oldSelection);


For every language EXCEPT Python, it works perfectly! I was very happy with the results. However, the CoffeeScript auto-indentation totally messes up with Phyton code.

It takes this file:

import sys

def factorial (n):
if n == 1:
return 1
else:
return n * factorial(n-1)

def foo:
print("blahblah")


And is unable to recognize where the factorial function ends, and thus indents like this:

import sys

def factorial (n):
if n == 1:
return 1
else:
return n * factorial(n-1)

def foo:
print("blahblah")


If anyone has any insight into how to remedy this it would be greatly appreciated!

Answer Source

You can't auto-indent Python code, full stop.

Auto-indentation only works for languages where blocks are delineated by explicit start- and end markers, such as curly braces. Indentation in such languages is essentially optional, only used by the human software developer to aid reading.

But in Python indentation carries meaning; how code is executed changes with the indentation. Asking software to decide how much indentation to apply is like asking for the computer to read your mind, to second-guess what the programmer wanted the code to do to begin with.

For example, the following in-indented code can be indented in different ways, and lead to different results. Which one interpretation is correct?

var = 'foobar'
if var.startswith('foo'):
print('Hello')
var += 'spam'
if var.endswith('bar'):
print('World')

It doesn't matter that you see the if __name__ == '__main__': test as a top-level statement. Python can't know that, and such a test would be legal anywhere in Python code, and may even make sense inside a function or class definition sometimes.