[IndentDetector] CONTINUATION_WITHOUT_FIRST indent of the outermost block is treated as CONTINUATION, while the rest are treated as NONE

Every null indent retrieved from Block build by FormattingModelBuilder.buildBlocks is converted to CONTINUATION_WITHOUT_FIRST.  Nested blocks starts the same offset and are retrieved as first block of it's parent that's why CONTINUATION_WITHOUT_FIRST works in such a case as NONE (because they are literally first blocks, see CWF javadoc)
This commit is contained in:
Yaroslav Lepenkin
2015-09-15 16:27:00 +03:00
parent 8d9f639786
commit 5131b4a55c
3 changed files with 95 additions and 19 deletions
@@ -0,0 +1,32 @@
<Block start="0" end="50">
<Indent type="NONE"/>
<Block start="0" end="13">
<Indent type="NONE"/>
</Block>
<Block start="18" end="35">
<Indent type="NONE"/>
<Block start="18" end="25">
<Indent type="NORMAL"/>
<Block start="18" end="25">
<Indent type="NONE"/>
<Block start="18" end="19"/>
<Block start="20" end="25">
<Indent type="NONE"/>
</Block>
</Block>
</Block>
<Block start="30" end="35">
<Indent type="NORMAL"/>
<Block start="30" end="35">
<Indent type="NONE"/>
<Block start="30" end="31"/>
<Block start="32" end="35">
<Indent type="NONE"/>
</Block>
</Block>
</Block>
</Block>
<Block start="36" end="50">
<Indent type="NONE"/>
</Block>
</Block>
@@ -40,17 +40,32 @@ public class FormatterBasedLineInfoBuilderTest extends LightPlatformCodeInsightT
String text = "/**\n" +
" *\n" +
" */";
List<LineIndentInfo> infos = getLineInfos(text);
assertLinesWithNormalIndent(infos, 0);
}
public void testXmlContinuationWithoutFirst() throws IOException, JDOMException {
String text = "<idea-plugin>\n" +
" <name/>\n" +
" <id/>\n" +
"</idea-plugin>";
List<LineIndentInfo> infos = getLineInfos(text);
assertLinesWithNormalIndent(infos, 4);
}
private static void assertLinesWithNormalIndent(List<LineIndentInfo> infos, int expected) {
long linesWithNormalIndent = infos.stream().filter(LineIndentInfo::isLineWithNormalIndent).count();
assertEquals(expected, linesWithNormalIndent);
}
private List<LineIndentInfo> getLineInfos(String text) throws IOException, JDOMException {
String file = getTestName(false) + ".xml";
TestFormattingModel model = new TestFormattingModel(text);
Document document = model.getDocument();
TestBlock block = new FormattingModelXmlReader(model).readTestBlock(getTestDataPath(), file);
FormatterBasedLineIndentInfoBuilder builder = new FormatterBasedLineIndentInfoBuilder(document, block);
List<LineIndentInfo> infos = builder.build();
long linesWithNormalIndents = infos.stream().filter(LineIndentInfo::isLineWithNormalIndent).count();
assertEquals(0, linesWithNormalIndents);
return builder.build();
}
}
@@ -19,6 +19,7 @@ import com.intellij.formatting.ASTBlock;
import com.intellij.formatting.Block;
import com.intellij.formatting.Indent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiComment;
import com.intellij.psi.formatter.common.AbstractBlock;
@@ -58,7 +59,7 @@ public class FormatterBasedLineIndentInfoBuilder {
return LineIndentInfo.LINE_WITH_TABS;
}
if (hasTotallyNormalOrNoneIndent(newLineBlock)) {
if (hasNormalIndent(newLineBlock)) {
return LineIndentInfo.newNormalIndent(blockStartOffset - lineStartOffset);
}
else {
@@ -68,22 +69,50 @@ public class FormatterBasedLineIndentInfoBuilder {
});
}
private static boolean hasTotallyNormalOrNoneIndent(Block block) {
private static boolean hasNormalIndent(Block block) {
final TextRange range = block.getTextRange();
final int startOffset = range.getStartOffset();
boolean startOffsetAlreadyHasNormalIndent = false;
while (block != null && range.getStartOffset() == startOffset) {
Indent.Type type = block.getIndent() != null ? block.getIndent().getType() : null;
if (type == Indent.Type.NONE || type == Indent.Type.NORMAL && !startOffsetAlreadyHasNormalIndent) {
startOffsetAlreadyHasNormalIndent = true;
List<Indent.Type> allIndents = getIndentOnStartOffset(block, range, startOffset);
if (hasOnlyNormalOrNoneIndents(allIndents)) {
int normalIndents = ContainerUtil.filter(allIndents, new Condition<Indent.Type>() {
@Override
public boolean value(Indent.Type type) {
return type == Indent.Type.NORMAL;
}
else {
}).size();
return normalIndents < 2;
}
return false;
}
private static boolean hasOnlyNormalOrNoneIndents(List<Indent.Type> indents) {
Indent.Type outerMostIndent = indents.get(0);
if (outerMostIndent != Indent.Type.NONE && outerMostIndent != Indent.Type.NORMAL) {
return false;
}
List<Indent.Type> innerIndents = indents.subList(1, indents.size());
for (Indent.Type indent : innerIndents) {
if (indent != Indent.Type.NONE && indent != Indent.Type.NORMAL
&& indent != Indent.Type.CONTINUATION_WITHOUT_FIRST) {
//continuation without first here because it is CONTINUATION only if it's owner is not the first child
return false;
}
}
return true;
}
private static List<Indent.Type> getIndentOnStartOffset(Block block, TextRange range, int startOffset) {
List<Indent.Type> indentsOnStartOffset = new ArrayList<Indent.Type>();
while (block != null && range.getStartOffset() == startOffset) {
Indent.Type type = block.getIndent() != null ? block.getIndent().getType() : Indent.Type.CONTINUATION_WITHOUT_FIRST;
indentsOnStartOffset.add(type);
if (block instanceof AbstractBlock) {
((AbstractBlock)block).setBuildIndentsOnly(true);
}
@@ -91,7 +120,7 @@ public class FormatterBasedLineIndentInfoBuilder {
block = subBlocks.isEmpty() ? null : subBlocks.get(0);
}
return true;
return indentsOnStartOffset;
}
@NotNull