tweak parsing of incomplete dict literals, consistent alignment/indentation when pressing Enter between dict key and value (PY-1469)

This commit is contained in:
Dmitry Jemerov
2011-01-26 20:22:58 +01:00
parent 38d3fe6504
commit ca1f5b8098
6 changed files with 79 additions and 8 deletions
@@ -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;
}
+1
View File
@@ -0,0 +1 @@
some_dict = { 'key': }
+18
View File
@@ -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);
}