Ответ 1
У Atom есть встроенный инструмент для этого
Активируйте палитру команд (Shift Cmd P на Mac, Ctrl Shift P в Windows/Linux) и найдите "конвертировать пространство" или "конвертировать вкладку". Вы должны найти эти три команды:
- Пробел: преобразование пространств в вкладки
- Пробел: конвертирование вкладок в пробелы
- Пробелы: конвертировать все вкладки в пробелы
Конвертировать вкладки и конвертировать все вкладки
В комментариях вы заметили, что использование "Преобразовать вкладки в пробелы" приведет к поломке отступа в Python, но "Конвертировать все вкладки в пробелы" работает правильно. Вы спросили, какая разница между ними.
Я не знал ответа, поэтому посмотрел. Это определено в пакете "whitespace", источник которого можно найти в Github в atom/whitespace.
Глядя в lib/whitespace.js, я нашел это:
'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)
}
}
Как вы можете видеть, здесь важна функция convertTabsToSpaces
. В варианте "convert all" единственное отличие состоит в том, что передается второй (необязательный) аргумент и устанавливается в true
.
return this.convertTabsToSpaces(editor, true)
Рассматривая определение convertTabsToSpaces
, разница заключается в том, что регулярное выражение изменяется в зависимости от состояния этого логического аргумента.
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)
}
Соответствующая строка здесь:
let regex = (convertAllTabs ? /\t/g : /^\t+/g)
Таким образом, в варианте "конвертировать все" регулярное выражение не заботится о привязке к началу строки (^
не используется), и каждая вкладка является собственной заменой (а не группами символов табуляции, обрабатываемых как одна замена - \t
против \t+
).
Почему это сломало отступ Python
Я не знаю, какой файл вы использовали, но я использовал довольно простой тестовый файл, подобный этому, полностью отступом с символами табуляции.
import foo
class Foo():
def __init__(self):
self.foo = True
def bar(self, a, b):
return a + b
После использования "Конвертировать вкладки в пробелы" это выглядело так:
import foo
class Foo():
def __init__(self):
self.foo = True
def bar(self, a, b):
return a + b
Ого! Это теперь SyntaxError
. Повторите попытку с помощью "Преобразовать все вкладки в пробелы":
import foo
class Foo():
def __init__(self):
self.foo = True
def bar(self, a, b):
return a + b
Это происходит потому, что в первом случае группы вкладок на левом поле, как коллекция, сводятся к пространственному отступу. Поскольку регулярное выражение есть ^\t+
, не имеет значения, если строка имеет отступ с 1, 2, 8, 24 вкладками... все они заменяются одним уровнем отступа, но сделаны из пробелов.
Честно говоря, я не знаю, в чем дело... это похоже на ошибку.
Во втором случае каждая вкладка преобразуется в эквивалентную ширину на основе пространства (т.е. каждая вкладка преобразуется в 4 пробела, даже если она смежна с другим символом табуляции).
Так что вы, возможно, захотите.
Одно предостережение: это уже не ограничивается левого края (нет ^
якорь), так что если вы встроили символы табуляции в другом месте, те также будут преобразованы. Это не нормальная практика в коде в моем опыте, но FYI, если это имеет для вас значение.