As I started working with Atom text editor, I used tab-indentation but want to change to 4-space-indentation.
I have several files that should be updated accordingly
What would be the easiest way to do it?
There is no canonical value for the number of spaces that = 1 tab in python (I like 4, but that's just me). What you can do is read the file in and search for \t characters, and replace those with however many spaces you need.
Atom soft tabs aren't configurable the way hard tabs are, that's why this package comes to the rescue: it provide an easy way to display consistent soft tabs length between different editors configurations. Pretend that your are working on a project with soft tabs of 2 spaces .
Activate the command palette (ShiftCmdP on Mac, CtrlShiftP on Windows/Linux) and search for "convert space" or "convert tab". You should find these three commands are available:
In the comments you observed that using "Convert Tabs to Spaces" would break indentation in Python, but "Convert All Tabs to Spaces" worked correctly. You asked what the difference between the two is.
I didn't know the answer, so I went looking. This is defined in the "whitespace" package, the source for which can be found on Github at atom/whitespace.
Looking in lib/whitespace.js, I found this:
'whitespace:convert-tabs-to-spaces': () => { let editor = atom.workspace.getActiveTextEditor() if (editor) { this.convertTabsToSpaces(editor) } }, 'whitespace:convert-spaces-to-tabs': () => { let editor = atom.workspace.getActiveTextEditor() if (editor) { return this.convertSpacesToTabs(editor) } }, 'whitespace:convert-all-tabs-to-spaces': () => { let editor = atom.workspace.getActiveTextEditor() if (editor) { return this.convertTabsToSpaces(editor, true) } }
As you can see, the relevant function here is convertTabsToSpaces
. In the "convert all" variant, the only difference is that a second (optional) argument is passed, and set to true
.
return this.convertTabsToSpaces(editor, true)
Looking at the definition of convertTabsToSpaces
, the difference is that the regex is changed based on the state of this boolean argument.
convertTabsToSpaces (editor, convertAllTabs) { let buffer = editor.getBuffer() let spacesText = new Array(editor.getTabLength() + 1).join(' ') let regex = (convertAllTabs ? /\t/g : /^\t+/g) buffer.transact(function () { return buffer.scan(regex, function ({replace}) { return replace(spacesText) }) }) return editor.setSoftTabs(true) }
The relevant line here is:
let regex = (convertAllTabs ? /\t/g : /^\t+/g)
So in the "convert all" variant, the regex does not care about being anchored to the beginning of the line (^
is not used), and each tab is is own replacement (rather than groups of tab characters being treated as a single replacement -- \t
vs. \t+
).
I don't know what file you used, but I used a pretty simple test file like this, indented completely with tab characters.
import foo class Foo(): def __init__(self): self.foo = True def bar(self, a, b): return a + b
After using "Convert Tabs to Spaces" it looked like this:
import foo class Foo(): def __init__(self): self.foo = True def bar(self, a, b): return a + b
Woah! That's now a SyntaxError
. Try again with "Convert All Tabs to Spaces":
import foo class Foo(): def __init__(self): self.foo = True def bar(self, a, b): return a + b
This happens because in the first case, groups of tabs on the left margin are, as a collection, reduced to a space-based indent. Since the regex is ^\t+
, it doesn't matter if the line is indented with 1, 2, 8, 24 tabs... they are all replaced with a single indent level, but made of spaces.
Honestly I don't know what the point of that is... that seems like a bug.
In the second case, every tab is converted to the equivalent space-based width (i.e. each tab is converted into 4 spaces, even if it is adjacent to another tab character).
So that's the one you probably want.
One caveat: it is no longer limited to the left margin (there is no ^
anchor), so if you have embedded tab characters elsewhere, those will also be converted. That is not a normal practice in code in my experience, but FYI, in case it matters to you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With