mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
tweak parsing of incomplete dict literals, consistent alignment/indentation when pressing Enter between dict key and value (PY-1469)
This commit is contained in:
@@ -171,6 +171,12 @@ public class PyBlock implements ASTBlock {
|
||||
childAlignment = getAlignmentForChildren();
|
||||
}
|
||||
}
|
||||
else if (parentType == PyElementTypes.KEY_VALUE_EXPRESSION) {
|
||||
PyKeyValueExpression keyValue = (PyKeyValueExpression) _node.getPsi();
|
||||
if (keyValue != null && child.getPsi() == keyValue.getValue()) {
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
}
|
||||
|
||||
if (isAfterStatementList(child) && !hasLineBreaksBefore(child, 2)) { // maybe enter was pressed and cut us from a previous (nested) statement list
|
||||
childIndent = Indent.getNormalIndent();
|
||||
@@ -543,6 +549,10 @@ public class PyBlock implements ASTBlock {
|
||||
if (elements.length == 0) {
|
||||
return null;
|
||||
}
|
||||
PyKeyValueExpression last = elements[elements.length-1];
|
||||
if (last.getValue() == null) { // incomplete
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return getAlignmentForChildren();
|
||||
}
|
||||
@@ -550,17 +560,12 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
|
||||
private Indent getChildIndent(int newChildIndex) {
|
||||
ASTNode afterNode = getAfterNode(newChildIndex);
|
||||
ASTNode lastChild = getLastNonSpaceChild(_node, false);
|
||||
if (lastChild != null && lastChild.getElementType() == PyElementTypes.STATEMENT_LIST && _subBlocks.size() >= newChildIndex) {
|
||||
if (newChildIndex == 0) { // block text contains backslash line wrappings, child block list not built
|
||||
if (afterNode == null) {
|
||||
return Indent.getNoneIndent();
|
||||
}
|
||||
int prevIndex = newChildIndex - 1;
|
||||
while (prevIndex > 0 && _subBlocks.get(prevIndex).getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT) {
|
||||
prevIndex--;
|
||||
}
|
||||
PyBlock insertAfterBlock = _subBlocks.get(prevIndex);
|
||||
ASTNode afterNode = insertAfterBlock.getNode();
|
||||
|
||||
// handle pressing Enter after colon and before first statement in
|
||||
// existing statement list
|
||||
@@ -614,6 +619,13 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
|
||||
if (afterNode != null && afterNode.getElementType() == PyElementTypes.KEY_VALUE_EXPRESSION) {
|
||||
PyKeyValueExpression keyValue = (PyKeyValueExpression) afterNode.getPsi();
|
||||
if (keyValue != null && keyValue.getValue() == null) { // incomplete
|
||||
return Indent.getContinuationIndent(true);
|
||||
}
|
||||
}
|
||||
|
||||
// constructs that imply indent for their children
|
||||
if (ourListElementTypes.contains(_node.getElementType()) || _node.getPsi() instanceof PyStatementPart) {
|
||||
return Indent.getNormalIndent();
|
||||
@@ -633,6 +645,19 @@ public class PyBlock implements ASTBlock {
|
||||
*/
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ASTNode getAfterNode(int newChildIndex) {
|
||||
if (newChildIndex == 0) { // block text contains backslash line wrappings, child block list not built
|
||||
return null;
|
||||
}
|
||||
int prevIndex = newChildIndex - 1;
|
||||
while (prevIndex > 0 && _subBlocks.get(prevIndex).getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT) {
|
||||
prevIndex--;
|
||||
}
|
||||
PyBlock insertAfterBlock = _subBlocks.get(prevIndex);
|
||||
return insertAfterBlock.getNode();
|
||||
}
|
||||
|
||||
private static ASTNode getLastNonSpaceChild(ASTNode node, boolean acceptError) {
|
||||
ASTNode lastChild = node.getLastChildNode();
|
||||
while (lastChild != null &&
|
||||
|
||||
@@ -188,7 +188,10 @@ public class ExpressionParsing extends Parsing {
|
||||
private void parseDictLiteralTail(PsiBuilder.Marker startMarker, PsiBuilder.Marker firstKeyValueMarker) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error("expression expected");
|
||||
firstKeyValueMarker.drop();
|
||||
firstKeyValueMarker.done(PyElementTypes.KEY_VALUE_EXPRESSION);
|
||||
if (atToken(PyTokenTypes.RBRACE)) {
|
||||
myBuilder.advanceLexer();
|
||||
}
|
||||
startMarker.done(PyElementTypes.DICT_LITERAL_EXPRESSION);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
some_dict = { 'key': }
|
||||
@@ -0,0 +1,18 @@
|
||||
PyFile:IncompleteDict.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: some_dict
|
||||
PsiElement(Py:IDENTIFIER)('some_dict')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyDictLiteralExpression
|
||||
PsiElement(Py:LBRACE)('{')
|
||||
PsiWhiteSpace(' ')
|
||||
PyKeyValueExpression
|
||||
PyStringLiteralExpression: key
|
||||
PsiElement(Py:STRING_LITERAL)(''key'')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiErrorElement:expression expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
@@ -94,6 +94,26 @@ public class PyIndentTest extends PyLightFixtureTestCase {
|
||||
"})");
|
||||
}
|
||||
|
||||
public void testIndentDictMissingValue() { // PY-1469
|
||||
doTest("some_dict = {\n" +
|
||||
" 'key': <caret>\n" +
|
||||
"}",
|
||||
"some_dict = {\n" +
|
||||
" 'key': \n" +
|
||||
" <caret>\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
public void testIndentDictStringValue() { // PY-1469
|
||||
doTest("some_dict = {\n" +
|
||||
" 'key': <caret>''\n" +
|
||||
"}",
|
||||
"some_dict = {\n" +
|
||||
" 'key': \n" +
|
||||
" <caret>''\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
public void testClass() {
|
||||
doTest("class A:\n" + " print a<caret>", "class A:\n" + " print a\n" + " <caret>");
|
||||
}
|
||||
|
||||
@@ -239,6 +239,10 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIncompleteDict() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void doTest() {
|
||||
doTest(LanguageLevel.PYTHON25);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user