diff --git a/java/java-tests/testData/psi/autodetect/XmlContinuationWithoutFirst.xml b/java/java-tests/testData/psi/autodetect/XmlContinuationWithoutFirst.xml new file mode 100644 index 000000000000..59deea200bf8 --- /dev/null +++ b/java/java-tests/testData/psi/autodetect/XmlContinuationWithoutFirst.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java index 2c23dcf010e9..9e3a35d9291c 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java @@ -40,17 +40,32 @@ public class FormatterBasedLineInfoBuilderTest extends LightPlatformCodeInsightT String text = "/**\n" + " *\n" + " */"; - + + List infos = getLineInfos(text); + assertLinesWithNormalIndent(infos, 0); + } + + public void testXmlContinuationWithoutFirst() throws IOException, JDOMException { + String text = "\n" + + " \n" + + " \n" + + ""; + + List infos = getLineInfos(text); + assertLinesWithNormalIndent(infos, 4); + } + + private static void assertLinesWithNormalIndent(List infos, int expected) { + long linesWithNormalIndent = infos.stream().filter(LineIndentInfo::isLineWithNormalIndent).count(); + assertEquals(expected, linesWithNormalIndent); + } + + private List 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 infos = builder.build(); - long linesWithNormalIndents = infos.stream().filter(LineIndentInfo::isLineWithNormalIndent).count(); - assertEquals(0, linesWithNormalIndents); + return builder.build(); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java index 7b1069be480f..c2dcc49b328d 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java @@ -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 allIndents = getIndentOnStartOffset(block, range, startOffset); + + if (hasOnlyNormalOrNoneIndents(allIndents)) { + int normalIndents = ContainerUtil.filter(allIndents, new Condition() { + @Override + public boolean value(Indent.Type type) { + return type == Indent.Type.NORMAL; } - else { + }).size(); + return normalIndents < 2; + } + + return false; + } + + private static boolean hasOnlyNormalOrNoneIndents(List indents) { + Indent.Type outerMostIndent = indents.get(0); + if (outerMostIndent != Indent.Type.NONE && outerMostIndent != Indent.Type.NORMAL) { + return false; + } + + List 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 getIndentOnStartOffset(Block block, TextRange range, int startOffset) { + List indentsOnStartOffset = new ArrayList(); + + 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