tweak alignment of comments between classes (PY-1598)

This commit is contained in:
Dmitry Jemerov
2010-11-01 22:34:05 +03:00
parent 0655a8f62f
commit f05662def4
7 changed files with 119 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
@@ -118,7 +119,7 @@ public class PyBlock implements ASTBlock {
Indent childIndent = Indent.getNoneIndent(); Indent childIndent = Indent.getNoneIndent();
Alignment childAlignment = null; Alignment childAlignment = null;
if (childType == PyElementTypes.STATEMENT_LIST || childType == PyElementTypes.IMPORT_ELEMENT) { if (childType == PyElementTypes.STATEMENT_LIST || childType == PyElementTypes.IMPORT_ELEMENT) {
if (hasLineBreakBefore(child)) { if (hasLineBreaksBefore(child, 1)) {
childIndent = Indent.getNormalIndent(); childIndent = Indent.getNormalIndent();
} }
} }
@@ -164,18 +165,26 @@ public class PyBlock implements ASTBlock {
childAlignment = getAlignmentForChildren(); childAlignment = getAlignmentForChildren();
} }
} }
try { // maybe enter was pressed and cut us from a previous (nested) statement list
if (isAfterStatementList(child) && !hasLineBreaksBefore(child, 2)) { // maybe enter was pressed and cut us from a previous (nested) statement list
childIndent = Indent.getNormalIndent();
}
return new PyBlock(child, childAlignment, childIndent, wrap, mySettings);
}
private static boolean isAfterStatementList(ASTNode child) {
try {
PsiElement prev = sure(child.getPsi().getPrevSibling()); PsiElement prev = sure(child.getPsi().getPrevSibling());
sure(prev instanceof PyStatement); sure(prev instanceof PyStatement);
PsiElement lastchild = PsiTreeUtil.getDeepestLast(prev); PsiElement lastchild = PsiTreeUtil.getDeepestLast(prev);
sure(lastchild.getParent() instanceof PyStatementList); sure(lastchild.getParent() instanceof PyStatementList);
childIndent = Indent.getNormalIndent(); return true;
} }
catch (IncorrectOperationException ignored) { catch (IncorrectOperationException e) {
// not our cup of tea // not our cup of tea
return false;
} }
return new PyBlock(child, childAlignment, childIndent, wrap, mySettings);
} }
private static boolean needListAlignment(ASTNode child) { private static boolean needListAlignment(ASTNode child) {
@@ -189,15 +198,22 @@ public class PyBlock implements ASTBlock {
return true; return true;
} }
private static boolean hasLineBreakBefore(ASTNode child) { private static boolean hasLineBreaksBefore(ASTNode child, int minCount) {
return isWhitespaceWithLineBreaks(child.getTreePrev()) || isWhitespaceWithLineBreaks(child.getFirstChildNode()); return isWhitespaceWithLineBreaks(TreeUtil.findLastLeaf(child.getTreePrev()), minCount) ||
isWhitespaceWithLineBreaks(child.getFirstChildNode(), minCount);
} }
private static boolean isWhitespaceWithLineBreaks(ASTNode node) { private static boolean isWhitespaceWithLineBreaks(ASTNode node, int minCount) {
if (node != null && node.getElementType() == TokenType.WHITE_SPACE) { if (node != null && node.getElementType() == TokenType.WHITE_SPACE) {
String prevNodeText = node.getText(); String prevNodeText = node.getText();
if (prevNodeText.indexOf('\n') >= 0) { int count = 0;
return true; for(int i=0; i<prevNodeText.length(); i++) {
if (prevNodeText.charAt(i) == '\n') {
count++;
if (count == minCount) {
return true;
}
}
} }
} }
return false; return false;
@@ -412,7 +428,7 @@ public class PyBlock implements ASTBlock {
// doesn't request childAttributes from the correct block // doesn't request childAttributes from the correct block
while (lastChild != null) { while (lastChild != null) {
IElementType last_type = lastChild.getElementType(); IElementType last_type = lastChild.getElementType();
if (last_type == PyElementTypes.STATEMENT_LIST && hasLineBreakBefore(lastChild)) { if (last_type == PyElementTypes.STATEMENT_LIST && hasLineBreaksBefore(lastChild, 1)) {
if (dedentAfterLastStatement((PyStatementList)lastChild.getPsi())) { if (dedentAfterLastStatement((PyStatementList)lastChild.getPsi())) {
break; break;
} }

View File

@@ -0,0 +1,9 @@
class T1(object):
def m1(self):
pass
# comment about T2
class T2(object):
def m2(self):
pass

View File

@@ -0,0 +1,9 @@
class T1(object):
def m1(self):
pass
# comment about T2
class T2(object):
def m2(self):
pass

View File

@@ -0,0 +1,9 @@
class T1(object):
def m1(self):
pass
# comment about T2
class T2(object):
def m2(self):
pass

View File

@@ -0,0 +1,56 @@
PyFile:CommentBetweenClasses.py
PyClass: T1
PsiElement(Py:CLASS_KEYWORD)('class')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('T1')
PyArgumentList
PsiElement(Py:LPAR)('(')
PyReferenceExpression: object
PsiElement(Py:IDENTIFIER)('object')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyFunction('m1')
PsiElement(Py:DEF_KEYWORD)('def')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('m1')
PyParameterList
PsiElement(Py:LPAR)('(')
PyNamedParameter('self')
PsiElement(Py:IDENTIFIER)('self')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n\n')
PsiComment(Py:END_OF_LINE_COMMENT)('# comment about T2')
PsiWhiteSpace('\n\n')
PyClass: T2
PsiElement(Py:CLASS_KEYWORD)('class')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('T2')
PyArgumentList
PsiElement(Py:LPAR)('(')
PyReferenceExpression: object
PsiElement(Py:IDENTIFIER)('object')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyFunction('m2')
PsiElement(Py:DEF_KEYWORD)('def')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('m2')
PyParameterList
PsiElement(Py:LPAR)('(')
PyNamedParameter('self')
PsiElement(Py:IDENTIFIER)('self')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -88,6 +88,10 @@ public class PyFormatterTest extends PyLightFixtureTestCase {
doTest(); doTest();
} }
public void testCommentBetweenClasses() { // PY-1598
doTest();
}
private void doTest() { private void doTest() {
myFixture.configureByFile("formatter/" + getTestName(true) + ".py"); myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
ApplicationManager.getApplication().runWriteAction(new Runnable() { ApplicationManager.getApplication().runWriteAction(new Runnable() {

View File

@@ -235,6 +235,10 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(); doTest();
} }
public void testCommentBetweenClasses() { // PY-1598
doTest();
}
public void doTest() { public void doTest() {
doTest(LanguageLevel.PYTHON25); doTest(LanguageLevel.PYTHON25);
} }