From 6aaf437b670cba8441c52db78bda9ced7e47cf99 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 3 Feb 2014 12:23:08 +0400 Subject: [PATCH] Space after '#' according to PEP8 (PY-11571). --- python/src/META-INF/python-core.xml | 1 + .../python/formatter/PyCodeStyleSettings.java | 2 + .../PyLanguageCodeStyleSettingsProvider.java | 6 +- .../formatter/PyPreFormatProcessor.java | 96 +++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 6c4665d91e20..8a9fe46241eb 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -18,6 +18,7 @@ + diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java index 961ca725506a..e727ddb8a05d 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java @@ -38,6 +38,8 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public boolean NEW_LINE_AFTER_COLON = false; public boolean NEW_LINE_AFTER_COLON_MULTI_CLAUSE = true; + public boolean SPACE_AFTER_NUMBER_SIGN = true; + public PyCodeStyleSettings(CodeStyleSettings container) { super("Python", container); } diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java index c26a1a1742bd..a7c6fc88331b 100644 --- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java +++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java @@ -72,9 +72,11 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT", "Around = in keyword argument", SPACES_AROUND_OPERATORS); consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_WITHIN_BRACES", "Braces", SPACES_WITHIN); - consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_BEFORE_PY_COLON", ApplicationBundle.message("checkbox.spaces.before.colon"), SPACES_OTHER); + consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_BEFORE_PY_COLON", + ApplicationBundle.message("checkbox.spaces.before.colon"), SPACES_OTHER); consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_AFTER_PY_COLON", ApplicationBundle.message("checkbox.spaces.after.colon"), SPACES_OTHER); consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_BEFORE_BACKSLASH", "Before '\\'", SPACES_OTHER); + consumer.showCustomOption(PyCodeStyleSettings.class, "SPACE_AFTER_NUMBER_SIGN", "After '#'", SPACES_OTHER); } else if (settingsType == SettingsType.BLANK_LINES_SETTINGS) { consumer.showStandardOptions("BLANK_LINES_AROUND_CLASS", @@ -112,7 +114,7 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin CommonCodeStyleSettings.IndentOptions indentOptions = defaultSettings.initIndentOptions(); indentOptions.INDENT_SIZE = 4; defaultSettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; - return defaultSettings; + return defaultSettings; } @Override diff --git a/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java new file mode 100644 index 000000000000..081efc27b72f --- /dev/null +++ b/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.formatter; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.impl.source.codeStyle.PreFormatProcessor; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.PyRecursiveElementVisitor; +import org.jetbrains.annotations.NotNull; + +/** + * @author traff + */ +public class PyPreFormatProcessor implements PreFormatProcessor { + @NotNull + @Override + public TextRange process(@NotNull ASTNode element, @NotNull TextRange range) { + PsiElement psiElement = element.getPsi(); + if (psiElement == null) return range; + + if (!psiElement.getLanguage().is(PythonLanguage.getInstance())) return range; + + PsiFile file = psiElement.isValid() ? psiElement.getContainingFile() : null; + if (file == null) return range; + + Project project = psiElement.getProject(); + + return new PyCommentFormatter(project).process(psiElement, range); + } + + /** + * @author traff + */ + public static class PyCommentFormatter extends PyRecursiveElementVisitor { + private final Project myProject; + private final CodeStyleSettings mySettings; + private final PyCodeStyleSettings myPyCodeStyleSettings; + private TextRange myRange; + + public PyCommentFormatter(Project project) { + myProject = project; + mySettings = CodeStyleSettingsManager.getSettings(project); + myPyCodeStyleSettings = mySettings.getCustomSettings(PyCodeStyleSettings.class); + } + + public TextRange process(PsiElement element, TextRange range) { + if (!myPyCodeStyleSettings.SPACE_AFTER_NUMBER_SIGN) { + return range; + } + myRange = range; + element.accept(this); + return element.getTextRange(); + } + + @Override + public void visitComment(PsiComment element) { + if (!myRange.contains(element.getTextRange())) { + return; + } + String text = element.getText(); + int commentStart = text.indexOf('#'); + if (commentStart != -1 && (commentStart + 1) < text.length()) { + String commentText = StringUtil.trimLeading(text.substring(commentStart + 1)); + + String newText = "# " + commentText; + if (!newText.equals(text)) { + element.replace( + PyElementGenerator.getInstance(myProject).createFromText(LanguageLevel.getDefault(), PsiComment.class, newText)); + } + } + } + } +}