diff --git a/java/java-tests/testData/psi/autodetect/FirstBlockOnNewLine_NotStartsIt.xml b/java/java-tests/testData/psi/autodetect/FirstBlockOnNewLine_NotStartsIt.xml
new file mode 100644
index 000000000000..0beebd746e23
--- /dev/null
+++ b/java/java-tests/testData/psi/autodetect/FirstBlockOnNewLine_NotStartsIt.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java
index 7e7e7a35ef2c..71fa8c72a04d 100644
--- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java
+++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java
@@ -15,9 +15,7 @@
*/
package com.intellij.psi.codeStyle.autodetect;
-import com.intellij.formatting.Block;
-import com.intellij.formatting.FormattingModel;
-import com.intellij.formatting.FormattingModelBuilder;
+import com.intellij.formatting.*;
import com.intellij.lang.LanguageFormatting;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiDocumentManager;
@@ -37,21 +35,22 @@ public abstract class AbstractNewLineBlocksIteratorTest extends LightPlatformCod
return getTestName(true);
}
- protected void checkNewLineBlocksStartOffsets(int[] newLineStartOffsets) {
- Iterator iterator = createNewLineBlocksIterator();
-
+ protected void checkStartOffsets(int[] newLineStartOffset) {
+ checkStartOffsets(newLineStartOffset, newLineBlockIterator());
+ }
+
+ protected void checkStartOffsets(int[] newLineStartOffsets, Iterator iterator) {
int i = 0;
while (iterator.hasNext()) {
- Assert.assertTrue("Detected unspecified new line block start offset ", i < newLineStartOffsets.length);
Block next = iterator.next();
+ Assert.assertTrue("Extra new line block found: " + next.getTextRange(), i < newLineStartOffsets.length);
Assert.assertEquals("Block start offset do not match ", newLineStartOffsets[i++], next.getTextRange().getStartOffset());
}
-
Assert.assertEquals("Not detected new line block start offset ", i, newLineStartOffsets.length);
}
@NotNull
- protected static Iterator createNewLineBlocksIterator() {
+ protected static Iterator newLineBlockIterator() {
FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(myFile);
Assert.assertNotNull(builder);
diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/NewLineBlocksIteratorTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/NewLineBlocksIteratorTest.java
index 38225ac553f5..8448949f8828 100644
--- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/NewLineBlocksIteratorTest.java
+++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/NewLineBlocksIteratorTest.java
@@ -17,8 +17,15 @@ package com.intellij.psi.codeStyle.autodetect;
import com.intellij.JavaTestUtil;
import com.intellij.formatting.Block;
+import com.intellij.formatting.FormattingModelXmlReader;
+import com.intellij.formatting.TestBlock;
+import com.intellij.formatting.TestFormattingModel;
+import com.intellij.openapi.editor.Document;
+import com.intellij.psi.formatter.common.NewLineBlocksIterator;
+import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
+import java.io.IOException;
import java.util.Iterator;
public class NewLineBlocksIteratorTest extends AbstractNewLineBlocksIteratorTest {
@@ -37,7 +44,7 @@ public class NewLineBlocksIteratorTest extends AbstractNewLineBlocksIteratorTest
0, 3, 30, 60, 82, 107, 136, 154, 184, 220, 226, 232, 237
};
- checkNewLineBlocksStartOffsets(newLineBlocksStartOffsets);
+ checkStartOffsets(newLineBlocksStartOffsets);
}
public void testDoNotReverseBlocks() {
@@ -47,15 +54,30 @@ public class NewLineBlocksIteratorTest extends AbstractNewLineBlocksIteratorTest
0, 39, 48, 118, 177, 235, 243
};
- checkNewLineBlocksStartOffsets(newLineBlocksStartOffsets);
+ checkStartOffsets(newLineBlocksStartOffsets);
}
+ public void testFirstBlockOnNewLine_NotStartsIt() throws IOException, JDOMException {
+ String text = "var x = r'''\n" +
+ "''';";
+
+ Iterator it = newIteratorFromTestFormattingModel(text);
+ checkStartOffsets(new int[] {0}, it);
+ }
+
+
public void testBigFileWithOnlyErrorElements_DoNotProduceSOE() {
configureByFile(getFileName() + ".java");
- Iterator iterator = createNewLineBlocksIterator();
+ Iterator iterator = newLineBlockIterator();
while (iterator.hasNext()) {
iterator.next();
}
}
-
+
+ protected Iterator newIteratorFromTestFormattingModel(String text) throws IOException, JDOMException {
+ TestFormattingModel model = new TestFormattingModel(text);
+ Document document = model.getDocument();
+ TestBlock block = new FormattingModelXmlReader(model).readTestBlock(getTestDataPath(), getFileName() + ".xml");
+ return new NewLineBlocksIterator(block, document);
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java
index 25e8669c9241..c03b079e3568 100644
--- a/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java
+++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java
@@ -18,6 +18,7 @@ package com.intellij.psi.formatter.common;
import com.intellij.formatting.Block;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
+import com.intellij.util.text.CharArrayUtil;
import java.util.Iterator;
import java.util.List;
@@ -44,15 +45,32 @@ public class NewLineBlocksIterator implements Iterator {
@Override
public boolean hasNext() {
if (myCurrentDocumentLine < myTotalLines) {
- popUntilTopBlockStartOffsetGreaterOrEqual(myCurrentLineStartOffset);
+ popUntilTopBlockStartsNewLine();
return !myStack.isEmpty();
}
return false;
}
+ private void popUntilTopBlockStartsNewLine() {
+ popUntilTopBlockStartOffsetGreaterOrEqual(myCurrentLineStartOffset);
+ if (myStack.isEmpty()) return;
+
+ Block block = myStack.peek();
+ while (block != null && !isStartingNewLine(block)) {
+ myCurrentDocumentLine++;
+ if (myCurrentDocumentLine >= myTotalLines) {
+ myStack.clear();
+ break;
+ }
+ myCurrentLineStartOffset = myDocument.getLineStartOffset(myCurrentDocumentLine);
+ popUntilTopBlockStartOffsetGreaterOrEqual(myCurrentLineStartOffset);
+ block = myStack.isEmpty() ? null : myStack.peek();
+ }
+ }
+
@Override
public Block next() {
- popUntilTopBlockStartOffsetGreaterOrEqual(myCurrentLineStartOffset);
+ popUntilTopBlockStartsNewLine();
Block current = myStack.peek();
TextRange currentBlockRange = current.getTextRange();
@@ -101,6 +119,17 @@ public class NewLineBlocksIterator implements Iterator {
}
}
+ private boolean isStartingNewLine(Block block) {
+ TextRange range = block.getTextRange();
+ int blockStart = range.getStartOffset();
+
+ int lineNumber = myDocument.getLineNumber(blockStart);
+ int lineStartOffset = myDocument.getLineStartOffset(lineNumber);
+
+ CharSequence text = myDocument.getCharsSequence();
+ return CharArrayUtil.isEmptyOrSpaces(text, lineStartOffset, blockStart);
+ }
+
@Override
public void remove() {
throw new UnsupportedOperationException();
diff --git a/platform/platform-tests/testSrc/com/intellij/formatting/FormattingModelXmlReader.java b/platform/platform-tests/testSrc/com/intellij/formatting/FormattingModelXmlReader.java
index 505e2dfcc0da..c6854c19c00e 100644
--- a/platform/platform-tests/testSrc/com/intellij/formatting/FormattingModelXmlReader.java
+++ b/platform/platform-tests/testSrc/com/intellij/formatting/FormattingModelXmlReader.java
@@ -28,6 +28,11 @@ import java.util.Map;
"/platform/platform-tests/testData/newGeneralFormatter", dataName + ".xml");
return readBlock(JDOMUtil.load(dataFile));
}
+
+ public TestBlock readTestBlock(String path, String file) throws IOException, JDOMException {
+ final File dataFile = new File(path, file);
+ return readBlock(JDOMUtil.load(dataFile));
+ }
private TestBlock readBlock(final Element rootElement) {
final int startOffset = Integer.parseInt(rootElement.getAttributeValue("start"));