mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
PY-14838, PY-13955 Do not align function arguments when first of them contains "hanging indent"
Regardless of option "Align multiline call arguments", alignment should
take place only when there is no, so called, "hanging indent" in function
call (see PEP-8). In accordance to behavior of 'pep8' utility several such
indents at the end of line are collapsed into one. E.g. fragment
'func([{\n' is considered as having "hanging indent" both for function
call, list and dict literals.
This commit is contained in:
@@ -243,12 +243,13 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
//Align elements vertically if there is an argument in the first line of parenthesized expression
|
||||
else if (((parentType == PyElementTypes.PARENTHESIZED_EXPRESSION && myContext.getSettings().ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION)
|
||||
|| (parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS)
|
||||
|| (parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) &&
|
||||
else if (!hasHangingIndent(_node.getPsi()) &&
|
||||
((parentType == PyElementTypes.PARENTHESIZED_EXPRESSION && myContext.getSettings().ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION) ||
|
||||
(parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) ||
|
||||
(parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) &&
|
||||
!isIndentNext(child) &&
|
||||
!hasLineBreaksBefore(_node.getFirstChildNode(), 1)
|
||||
&& !ourListElementTypes.contains(childType)) {
|
||||
!hasLineBreaksBefore(_node.getFirstChildNode(), 1) &&
|
||||
!ourListElementTypes.contains(childType)) {
|
||||
|
||||
if (!ourBrackets.contains(childType)) {
|
||||
childAlignment = getAlignmentForChildren();
|
||||
@@ -325,6 +326,35 @@ public class PyBlock implements ASTBlock {
|
||||
return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext);
|
||||
}
|
||||
|
||||
// Check https://www.python.org/dev/peps/pep-0008/#indentation
|
||||
private boolean hasHangingIndent(@NotNull PsiElement elem) {
|
||||
final PsiElement[] items;
|
||||
if (elem instanceof PyCallExpression) {
|
||||
final PyArgumentList argumentList = ((PyCallExpression)elem).getArgumentList();
|
||||
return argumentList != null && hasHangingIndent(argumentList);
|
||||
}
|
||||
else if (elem instanceof PyFunction) {
|
||||
return hasHangingIndent(((PyFunction)elem).getParameterList());
|
||||
}
|
||||
else if (elem instanceof PySequenceExpression) {
|
||||
items = ((PySequenceExpression)elem).getElements();
|
||||
}
|
||||
else if (elem instanceof PyParameterList) {
|
||||
items = ((PyParameterList)elem).getParameters();
|
||||
}
|
||||
else if (elem instanceof PyArgumentList) {
|
||||
items = ((PyArgumentList)elem).getArguments();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (items.length == 0) {
|
||||
return true;
|
||||
}
|
||||
final PsiElement firstItem = items[0];
|
||||
return hasLineBreaksBefore(firstItem.getNode(), 1) || hasHangingIndent(firstItem);
|
||||
}
|
||||
|
||||
private static boolean breaksAlignment(IElementType type) {
|
||||
return type != PyElementTypes.BINARY_EXPRESSION;
|
||||
}
|
||||
@@ -412,7 +442,7 @@ public class PyBlock implements ASTBlock {
|
||||
return false;
|
||||
}
|
||||
if (_node.getElementType() == PyElementTypes.ARGUMENT_LIST) {
|
||||
if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) {
|
||||
if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS || hasHangingIndent(_node.getPsi())) {
|
||||
return false;
|
||||
}
|
||||
if (child.getElementType() == PyTokenTypes.COMMA) {
|
||||
@@ -427,7 +457,7 @@ public class PyBlock implements ASTBlock {
|
||||
return false;
|
||||
}
|
||||
if (_node.getElementType() == PyElementTypes.PARAMETER_LIST) {
|
||||
return myContext.getSettings().ALIGN_MULTILINE_PARAMETERS;
|
||||
return !hasHangingIndent(_node.getPsi()) && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS;
|
||||
}
|
||||
if (_node.getElementType() == PyElementTypes.SUBSCRIPTION_EXPRESSION) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
def test_function(*args):
|
||||
pass
|
||||
|
||||
test_function({
|
||||
'a': 'b',
|
||||
}, 5)
|
||||
|
||||
test_function(1,
|
||||
2,
|
||||
3)
|
||||
@@ -0,0 +1,3 @@
|
||||
handler = webapp2.WSGIApplication([
|
||||
('/', UserHandler),<caret>
|
||||
], debug=True)
|
||||
@@ -0,0 +1,4 @@
|
||||
handler = webapp2.WSGIApplication([
|
||||
('/', UserHandler),
|
||||
()
|
||||
], debug=True)
|
||||
@@ -0,0 +1,11 @@
|
||||
def test_function(*args):
|
||||
pass
|
||||
|
||||
|
||||
test_function({
|
||||
'a': 'b',
|
||||
}, 5)
|
||||
|
||||
test_function(1,
|
||||
2,
|
||||
3)
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.formatter.PyCodeStyleSettings;
|
||||
@@ -159,7 +160,7 @@ public class PyFormatterTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testNoAlignForMethodArguments() { // PY-3995
|
||||
settings().getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false;
|
||||
getCommonSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false;
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -435,6 +436,36 @@ public class PyFormatterTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-14838
|
||||
public void testNoAlignmentAfterDictHangingIndentInFunctionCall() {
|
||||
getCommonSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
try {
|
||||
doTest();
|
||||
}
|
||||
finally {
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false;
|
||||
}
|
||||
}
|
||||
|
||||
// PY-13955
|
||||
public void testNoAlignmentAfterDictHangingIndentInFunctionCallOnTyping() {
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
try {
|
||||
final String testName = "formatter/" + getTestName(true);
|
||||
myFixture.configureByFile(testName + ".py");
|
||||
WriteCommandAction.runWriteCommandAction(null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myFixture.type("\n(");
|
||||
}
|
||||
});
|
||||
myFixture.checkResultByFile(testName + "_after.py");
|
||||
}
|
||||
finally {
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)}
|
||||
* is possible for Python sources.
|
||||
@@ -455,7 +486,11 @@ public class PyFormatterTest extends PyTestCase {
|
||||
myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py");
|
||||
}
|
||||
|
||||
private CommonCodeStyleSettings getCommonSettings() {
|
||||
return settings().getCommonSettings(PythonLanguage.getInstance());
|
||||
}
|
||||
|
||||
private CodeStyleSettings settings() {
|
||||
return CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject());
|
||||
return CodeStyleSettingsManager.getSettings(myFixture.getProject());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user