mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-20633 Allow to configure wrapping policy for names in a "from" import
This commit is contained in:
@@ -1033,7 +1033,7 @@ formatter.multi.clause.statements=Multi-clause statements
|
||||
formatter.force.new.line.after.colon=Force new line after colon
|
||||
formatter.align.when.multiline=Align when multiline
|
||||
formatter.collections.and.comprehensions=Collections and Comprehensions
|
||||
formatter.import.statements=Import Statements
|
||||
formatter.from.import.statements="From" Import Statements
|
||||
formatter.dictionary.literals=Dictionary literals
|
||||
formatter.hang.closing.brackets=Hang closing brackets
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -90,10 +89,13 @@ public class PyBlock implements ASTBlock {
|
||||
private final PyBlockContext myContext;
|
||||
private List<PyBlock> mySubBlocks = null;
|
||||
private Map<ASTNode, PyBlock> mySubBlockByNode = null;
|
||||
private Alignment myChildAlignment;
|
||||
private final Alignment myDictAlignment;
|
||||
private final Wrap myDictWrapping;
|
||||
private final boolean myEmptySequence;
|
||||
|
||||
// Shared among multiple children sub-blocks
|
||||
private Alignment myChildAlignment = null;
|
||||
private Alignment myDictAlignment = null;
|
||||
private Wrap myDictWrapping = null;
|
||||
private Wrap myFromImportWrapping = null;
|
||||
|
||||
public PyBlock(@Nullable PyBlock parent,
|
||||
@NotNull ASTNode node,
|
||||
@@ -109,13 +111,13 @@ public class PyBlock implements ASTBlock {
|
||||
myContext = context;
|
||||
myEmptySequence = isEmptySequence(node);
|
||||
|
||||
final PyCodeStyleSettings pySettings = myContext.getPySettings();
|
||||
if (node.getElementType() == PyElementTypes.DICT_LITERAL_EXPRESSION) {
|
||||
myDictAlignment = Alignment.createAlignment(true);
|
||||
myDictWrapping = Wrap.createWrap(myContext.getPySettings().DICT_WRAPPING, true);
|
||||
myDictWrapping = Wrap.createWrap(pySettings.DICT_WRAPPING, true);
|
||||
}
|
||||
else {
|
||||
myDictAlignment = null;
|
||||
myDictWrapping = null;
|
||||
else if (node.getElementType() == PyElementTypes.FROM_IMPORT_STATEMENT) {
|
||||
myFromImportWrapping = Wrap.createWrap(pySettings.FROM_IMPORT_WRAPPING, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,9 +186,11 @@ public class PyBlock implements ASTBlock {
|
||||
final IElementType grandparentType = grandParentNode == null ? null : grandParentNode.getElementType();
|
||||
|
||||
final IElementType childType = child.getElementType();
|
||||
Wrap wrap = null;
|
||||
Wrap childWrap = null;
|
||||
Indent childIndent = Indent.getNoneIndent();
|
||||
Alignment childAlignment = null;
|
||||
|
||||
final PyCodeStyleSettings settings = myContext.getPySettings();
|
||||
|
||||
if (parentType == PyElementTypes.BINARY_EXPRESSION && !isInControlStatement()) {
|
||||
//Setup alignments for binary expression
|
||||
@@ -220,7 +224,12 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
else if (childType == PyElementTypes.IMPORT_ELEMENT) {
|
||||
wrap = Wrap.createWrap(WrapType.NORMAL, true);
|
||||
if (parentType == PyElementTypes.FROM_IMPORT_STATEMENT) {
|
||||
childWrap = myFromImportWrapping;
|
||||
}
|
||||
else {
|
||||
childWrap = Wrap.createWrap(WrapType.NORMAL, true);
|
||||
}
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
if (childType == PyTokenTypes.END_OF_LINE_COMMENT && parentType == PyElementTypes.FROM_IMPORT_STATEMENT) {
|
||||
@@ -232,7 +241,7 @@ public class PyBlock implements ASTBlock {
|
||||
!ourBrackets.contains(childType) &&
|
||||
childType != PyTokenTypes.COMMA &&
|
||||
!isSliceOperand(child) /*&& !isSubscriptionOperand(child)*/) {
|
||||
wrap = Wrap.createWrap(WrapType.NORMAL, true);
|
||||
childWrap = Wrap.createWrap(WrapType.NORMAL, true);
|
||||
}
|
||||
if (needListAlignment(child) && !myEmptySequence) {
|
||||
childAlignment = getAlignmentForChildren();
|
||||
@@ -251,7 +260,7 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
|
||||
final PyCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(child.getPsi().getProject()).getCustomSettings(PyCodeStyleSettings.class);
|
||||
|
||||
if (parentType == PyElementTypes.LIST_LITERAL_EXPRESSION || parentType == PyElementTypes.LIST_COMP_EXPRESSION) {
|
||||
if ((childType == PyTokenTypes.RBRACKET && !settings.HANG_CLOSING_BRACKETS) || childType == PyTokenTypes.LBRACKET) {
|
||||
childIndent = Indent.getNoneIndent();
|
||||
@@ -370,7 +379,7 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
if (childType == PyElementTypes.KEY_VALUE_EXPRESSION && isChildOfDictLiteral(child)) {
|
||||
wrap = myDictWrapping;
|
||||
childWrap = myDictWrapping;
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
|
||||
@@ -406,7 +415,7 @@ public class PyBlock implements ASTBlock {
|
||||
prev = prev.getTreePrev();
|
||||
}
|
||||
|
||||
return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext);
|
||||
return new PyBlock(this, child, childAlignment, childIndent, childWrap, myContext);
|
||||
}
|
||||
|
||||
private static boolean isValueOfKeyValuePairOfDictLiteral(@NotNull ASTNode node) {
|
||||
|
||||
@@ -93,6 +93,11 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings {
|
||||
public boolean OPTIMIZE_IMPORTS_SORT_BY_TYPE_FIRST = true;
|
||||
public boolean OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE = false;
|
||||
|
||||
/**
|
||||
* Affects wrapping of multiple imported names in a single "from" import.
|
||||
*/
|
||||
public int FROM_IMPORT_WRAPPING = WrapType.NORMAL.getLegacyRepresentation();
|
||||
|
||||
/**
|
||||
* Corresponds to the option of pycodestyle.py "--hang-closing". Basically, it means that the closing brace of a collection literal,
|
||||
* a comprehension, an argument list, a parameter list or parentheses in "from" import statement should have the same indent as the items
|
||||
|
||||
@@ -119,9 +119,11 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin
|
||||
consumer.showCustomOption(PyCodeStyleSettings.class, "ALIGN_COLLECTIONS_AND_COMPREHENSIONS",
|
||||
PyBundle.message("formatter.align.when.multiline"),
|
||||
PyBundle.message("formatter.collections.and.comprehensions"));
|
||||
consumer.showCustomOption(PyCodeStyleSettings.class, "FROM_IMPORT_WRAPPING",
|
||||
PyBundle.message("formatter.from.import.statements"), null, WRAP_OPTIONS, WRAP_VALUES);
|
||||
consumer.showCustomOption(PyCodeStyleSettings.class, "ALIGN_MULTILINE_IMPORTS",
|
||||
PyBundle.message("formatter.align.when.multiline"),
|
||||
PyBundle.message("formatter.import.statements"));
|
||||
PyBundle.message("formatter.from.import.statements"));
|
||||
|
||||
consumer.showCustomOption(PyCodeStyleSettings.class, "DICT_WRAPPING",
|
||||
PyBundle.message("formatter.dictionary.literals"), null, WRAP_OPTIONS, WRAP_VALUES);
|
||||
@@ -177,14 +179,14 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin
|
||||
" def foo(self):\n" +
|
||||
" pass";
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static String WRAP_SETTINGS_PREVIEW = "from foo import (bar,\n" +
|
||||
" baz)\n" +
|
||||
private static String WRAP_SETTINGS_PREVIEW = "from module import (foo, bar, baz, quux,)\n" +
|
||||
"\n" +
|
||||
"long_expression = component_one + component_two + component_three + component_four + component_five + component_six\n" +
|
||||
"\n" +
|
||||
"def xyzzy(long_parameter_1,\n" +
|
||||
"long_parameter_2):\n" +
|
||||
" pass\n\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"xyzzy('long_string_constant1',\n" +
|
||||
" 'long_string_constant2')\n" +
|
||||
"\n" +
|
||||
@@ -201,7 +203,8 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin
|
||||
" 'eggs',\n" +
|
||||
"]\n" +
|
||||
"\n" +
|
||||
"if True: pass\n\n" +
|
||||
"if True: pass\n" +
|
||||
"\n" +
|
||||
"try: pass\n" +
|
||||
"finally: pass\n";
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from module import foo, bar
|
||||
from module import foo, bar, baz
|
||||
from module import (foo, bar)
|
||||
from module import (foo, bar, baz)
|
||||
@@ -0,0 +1,8 @@
|
||||
from module import foo, bar
|
||||
from module import foo, \
|
||||
bar, \
|
||||
baz
|
||||
from module import (foo, bar)
|
||||
from module import (foo,
|
||||
bar,
|
||||
baz)
|
||||
@@ -733,6 +733,13 @@ public class PyFormatterTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-20633
|
||||
public void testFromImportWrappingChopDownIfLong() {
|
||||
getPythonCodeStyleSettings().FROM_IMPORT_WRAPPING = WrapType.CHOP_DOWN_IF_LONG.getLegacyRepresentation();
|
||||
getCodeStyleSettings().setRightMargin(PythonLanguage.INSTANCE, 30);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testVariableAnnotations() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user