spacing options in Python formatter (PY-951)

This commit is contained in:
Dmitry Jemerov
2010-05-07 14:51:32 +04:00
parent 74672e8b09
commit b28c907bc6
13 changed files with 240 additions and 5 deletions
@@ -137,6 +137,9 @@ public class PyTokenTypes {
public static final TokenSet ADDITIVE_OPERATIONS = TokenSet.create(PLUS, MINUS);
public static final TokenSet MULTIPLICATIVE_OPERATIONS = TokenSet.create(MULT, FLOORDIV, DIV, PERC);
public static final TokenSet UNARY_OPERATIONS = TokenSet.create(PLUS, MINUS, TILDE);
public static final TokenSet BITWISE_OPERATIONS = TokenSet.create(AND, OR, XOR);
public static final TokenSet EQUALITY_OPERATIONS = TokenSet.create(EQEQ, NE, NE_OLD);
public static final TokenSet RELATIONAL_OPERATIONS = TokenSet.create(LT, GT, LE, GE);
public static final TokenSet END_OF_STATEMENT = TokenSet.create(STATEMENT_BREAK, SEMICOLON);
public static final TokenSet WHITESPACE = TokenSet.create(SPACE, TAB, FORMFEED);
public static final TokenSet WHITESPACE_OR_LINEBREAK = TokenSet.create(SPACE, TAB, FORMFEED, LINE_BREAK);
@@ -212,15 +212,71 @@ public class PyBlock implements ASTBlock {
if (type1 == PyTokenTypes.COLON && type2 == PyElementTypes.STATEMENT_LIST) {
return Spacing.createSpacing(1, Integer.MAX_VALUE, 0, true, 0);
}
if (type2 == PyTokenTypes.COLON) {
return getSpacingForOption(getPySettings().SPACE_BEFORE_COLON);
}
if (type1 == PyTokenTypes.COMMA) {
return getSpacingForOption(mySettings.SPACE_AFTER_COMMA);
}
/*
if (type1 == PyTokenTypes.COLON && type2 == PyElementTypes.STATEMENT_LIST) {
return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, true, Integer.MAX_VALUE);
}
*/
if (type2 == PyTokenTypes.COMMA) {
return getSpacingForOption(mySettings.SPACE_BEFORE_COMMA);
}
if (type2 == PyTokenTypes.SEMICOLON) {
return getSpacingForOption(mySettings.SPACE_BEFORE_SEMICOLON);
}
if (type1 == PyTokenTypes.LPAR || type2 == PyTokenTypes.RPAR) {
if (parentType == PyElementTypes.ARGUMENT_LIST) {
return getSpacingForOption(mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES);
}
}
if (type2 == PyTokenTypes.LBRACKET) {
return getSpacingForOption(getPySettings().SPACE_BEFORE_LBRACKET);
}
if (type1 == PyTokenTypes.LBRACKET || type2 == PyTokenTypes.RBRACKET) {
return getSpacingForOption(mySettings.SPACE_WITHIN_BRACKETS);
}
if (type1 == PyTokenTypes.LBRACE || type2 == PyTokenTypes.RBRACE) {
return getSpacingForOption(getPySettings().SPACE_WITHIN_BRACES);
}
if (type2 == PyElementTypes.ARGUMENT_LIST) {
return getSpacingForOption(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
if (type1 == PyTokenTypes.EQ || type2 == PyTokenTypes.EQ) {
if (parentType == PyElementTypes.ASSIGNMENT_STATEMENT) {
return getSpacingForOption(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
if (parentType == PyElementTypes.NAMED_PARAMETER) {
return getSpacingForOption(getPySettings().SPACE_AROUND_EQ_IN_NAMED_PARAMETER);
}
if (parentType == PyElementTypes.KEYWORD_ARGUMENT_EXPRESSION) {
return getSpacingForOption(getPySettings().SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT);
}
}
if (isAround(type1, type2, PyTokenTypes.AUG_ASSIGN_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.ADDITIVE_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_ADDITIVE_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.MULTIPLICATIVE_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.SHIFT_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_SHIFT_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.BITWISE_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_BITWISE_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.EQUALITY_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_EQUALITY_OPERATORS);
}
if (isAround(type1, type2, PyTokenTypes.RELATIONAL_OPERATIONS)) {
return getSpacingForOption(mySettings.SPACE_AROUND_RELATIONAL_OPERATORS);
}
//if (parentType == PyElementTypes.ARGUMENT_LIST
// || parentType == PyElementTypes.LIST_LITERAL_EXPRESSION) {
@@ -240,6 +296,14 @@ public class PyBlock implements ASTBlock {
return null;
}
private static boolean isAround(IElementType type1, IElementType type2, final TokenSet tokenSet) {
return tokenSet.contains(type1) || tokenSet.contains(type2);
}
private PyCodeStyleSettings getPySettings() {
return mySettings.getCustomSettings(PyCodeStyleSettings.class);
}
private Spacing getSpacingForOption(boolean isOptionSet) {
int spaces = isOptionSet ? 1 : 0;
return Spacing.createSpacing(spaces, spaces, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.formatter.PyCodeStylePanel">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</form>
@@ -0,0 +1,69 @@
package com.jetbrains.python.formatter;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.ide.highlighter.HighlighterFactory;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.jetbrains.python.PyHighlighter;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* @author yole
*/
public class PyCodeStylePanel extends CodeStyleAbstractPanel {
private JPanel myPanel;
protected PyCodeStylePanel(CodeStyleSettings settings) {
super(settings);
}
@Override
protected EditorHighlighter createHighlighter(EditorColorsScheme scheme) {
return HighlighterFactory.createHighlighter(new PyHighlighter(LanguageLevel.PYTHON26), scheme);
}
@Override
protected int getRightMargin() {
return 80;
}
@Override
protected void prepareForReformat(PsiFile psiFile) {
}
@NotNull
@Override
protected FileType getFileType() {
return PythonFileType.INSTANCE;
}
@Override
protected String getPreviewText() {
return "";
}
@Override
protected void resetImpl(CodeStyleSettings settings) {
}
@Override
public void apply(CodeStyleSettings settings) {
}
@Override
public boolean isModified(CodeStyleSettings settings) {
return false;
}
@Override
public JComponent getPanel() {
return myPanel;
}
}
@@ -0,0 +1,19 @@
package com.jetbrains.python.formatter;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
/**
* @author yole
*/
public class PyCodeStyleSettings extends CustomCodeStyleSettings {
public boolean SPACE_WITHIN_BRACES = false;
public boolean SPACE_BEFORE_COLON = false;
public boolean SPACE_BEFORE_LBRACKET = false;
public boolean SPACE_AROUND_EQ_IN_NAMED_PARAMETER = false;
public boolean SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT = false;
protected PyCodeStyleSettings(CodeStyleSettings container) {
super("Python", container);
}
}
@@ -0,0 +1,38 @@
package com.jetbrains.python.formatter;
import com.intellij.application.options.CodeStyleAbstractConfigurable;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.openapi.options.Configurable;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
@Override
public CustomCodeStyleSettings createCustomSettings(CodeStyleSettings settings) {
return new PyCodeStyleSettings(settings);
}
@NotNull
@Override
public Configurable createSettingsPage(CodeStyleSettings settings, CodeStyleSettings originalSettings) {
return new CodeStyleAbstractConfigurable(settings, originalSettings, "Ruby") {
protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) {
return new PyCodeStylePanel(settings);
}
public String getHelpTopic() {
return null;
}
};
}
@Override
public String getConfigurableDisplayName() {
return "Python";
}
}
@@ -0,0 +1,4 @@
spam( ham[ 1 ], { eggs: 2 } )
if x == 4 : print x , y ; x , y = y , x
spam (1)
dict ['key'] = list [index]
@@ -0,0 +1,4 @@
spam(ham[1], {eggs: 2})
if x == 4: print x, y; x, y = y, x
spam(1)
dict['key'] = list[index]
@@ -0,0 +1,2 @@
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
@@ -0,0 +1,2 @@
def complex(real, imag=0.0):
return magic(r=real, i=imag)
@@ -0,0 +1,3 @@
i=i+1
submitted+=1
x = x*2-1
@@ -0,0 +1,3 @@
i = i + 1
submitted += 1
x = x * 2 - 1
@@ -20,6 +20,18 @@ public class PyFormatterTest extends PyLightFixtureTestCase {
doTest();
}
public void testPep8ExtraneousWhitespace() throws Exception {
doTest();
}
public void testPep8Operators() throws Exception {
doTest();
}
public void testPep8KeywordArguments() throws Exception {
doTest();
}
private void doTest() throws Exception {
myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
ApplicationManager.getApplication().runWriteAction(new Runnable() {