diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java index 9c161f98dcf2..972086372833 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java @@ -37,11 +37,25 @@ public class JavaDocRenderTest extends AbstractEditorTest { " /** doc */\n" + " int a;\n" + "}\n", true); - verifyFoldingState("[FoldRegion +(10:23), placeholder='']"); + verifyFoldingState("[FoldRegion +(11:24), placeholder='']"); executeAction(IdeActions.ACTION_EDITOR_DELETE_LINE); checkResultByText("class C {\n" + - " /** doc */\n" + - " int a;\n" + + " /** doc */\n" + + " int a;\n" + + "}\n"); + } + + public void testTypingAtLineStart() { + configure("class C {\n" + + "/** doc */\n" + + "int a;\n" + + "}\n", true); + verifyFoldingState("[FoldRegion +(10:21), placeholder='']"); + executeAction(IdeActions.ACTION_EDITOR_MOVE_LINE_START); + type(' '); + checkResultByText("class C {\n" + + "/** doc */\n" + + " int a;\n" + "}\n"); } @@ -53,14 +67,14 @@ public class JavaDocRenderTest extends AbstractEditorTest { verifyFoldingState("[]"); verifyItem(12, 22, null); toggleItem(); - verifyFoldingState("[FoldRegion +(9:22), placeholder='']"); + verifyFoldingState("[FoldRegion +(10:23), placeholder='']"); verifyItem(12, 22, "doc"); toggleItem(); verifyFoldingState("[]"); verifyItem(12, 22, null); runWriteCommand(() -> getEditor().getDocument().setText(getEditor().getDocument().getText().replace("doc", "another"))); toggleItem(); - verifyFoldingState("[FoldRegion +(9:26), placeholder='']"); + verifyFoldingState("[FoldRegion +(10:27), placeholder='']"); verifyItem(12, 26, "another"); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderItem.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderItem.java index 88ae579ba6de..312422339f23 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderItem.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderItem.java @@ -407,18 +407,8 @@ public class DocRenderItem { Document document = highlighter.getDocument(); int startLine = document.getLineNumber(highlighter.getStartOffset()); int endLine = document.getLineNumber(highlighter.getEndOffset()); - int endOffset = document.getLineEndOffset(endLine); - int nextLineOffset = endLine < document.getLineCount() - 1 ? document.getLineStartOffset(endLine + 1) : endOffset; - if (startLine == 0) { - inlayOffset = 0; - foldStartOffset = 0; - foldEndOffset = nextLineOffset; - } - else { - inlayOffset = nextLineOffset; - foldStartOffset = document.getLineEndOffset(startLine - 1); - foldEndOffset = endOffset; - } + inlayOffset = foldStartOffset = document.getLineStartOffset(startLine); + foldEndOffset = endLine < document.getLineCount() - 1 ? document.getLineStartOffset(endLine + 1) : document.getLineEndOffset(endLine); } private boolean match(FoldRegion foldRegion, Inlay inlay) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index 3e245816a91f..2cf05a52ac62 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -676,7 +676,7 @@ public final class EditorUtil { public static int yPositionToLogicalLine(@NotNull Editor editor, int y) { int line = editor instanceof EditorImpl ? editor.yToVisualLine(y) : y / editor.getLineHeight(); - return line > 0 ? editor.visualToLogicalPosition(new VisualPosition(line, 0)).line : getFirstDisplayedLogicalLine(editor); + return editor.visualToLogicalPosition(new VisualPosition(line, 0)).line; } /** @@ -687,23 +687,7 @@ public final class EditorUtil { int visualLine = editor.yToVisualLine(y); int visualLineStartY = editor.visualLineToY(visualLine); if (y < visualLineStartY || y >= visualLineStartY + editor.getLineHeight()) return -1; - return visualLine > 0 ? editor.visualToLogicalPosition(new VisualPosition(visualLine, 0)).line : getFirstDisplayedLogicalLine(editor); - } - - /** - * This returns {@code 0}, unless there's a rendered documentation comment shown at the beginning of file. - */ - public static int getFirstDisplayedLogicalLine(@NotNull Editor editor) { - if (editor instanceof EditorEx) { - FoldRegion[] regions = ((EditorEx)editor).getFoldingModel().fetchTopLevel(); - if (regions != null && regions.length > 0) { - FoldRegion region = regions[0]; - if (region.shouldNeverExpand() && region.getStartOffset() == 0) { - return editor.getDocument().getLineNumber(region.getEndOffset()); - } - } - } - return 0; + return editor.visualToLogicalPosition(new VisualPosition(visualLine, 0)).line; } public static boolean isAtLineEnd(@NotNull Editor editor, int offset) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index f0df59cba900..916e6428b32f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -469,7 +469,7 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx implements VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, startVisualLine); while (!visLinesIterator.atEnd() && visLinesIterator.getVisualLine() <= endVisualLine) { - int logLine = getDisplayedLogicalLine(visLinesIterator); + int logLine = visLinesIterator.getDisplayedLogicalLine(); int y = visLinesIterator.getY(); paintAnnotationLine(g, gutterProvider, logLine, x, y, annotationSize, lineHeight); @@ -600,7 +600,7 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx implements VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, startVisualLine); while (!visLinesIterator.atEnd() && visLinesIterator.getVisualLine() <= endVisualLine) { if (!visLinesIterator.startsWithSoftWrap()) { - int logicalLine = getDisplayedLogicalLine(visLinesIterator); + int logicalLine = visLinesIterator.getDisplayedLogicalLine(); Integer lineToDisplay = converter.convert(myEditor, logicalLine + 1); if (lineToDisplay != null) { int startY = visLinesIterator.getY(); @@ -633,11 +633,6 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx implements } } - private int getDisplayedLogicalLine(VisualLinesIterator linesIterator) { - int logicalLine = linesIterator.getStartLogicalLine(); - return logicalLine == 0 ? EditorUtil.getFirstDisplayedLogicalLine(myEditor) : logicalLine; - } - private int endLineNumber() { return Math.max(0, myEditor.getDocument().getLineCount() - 1); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java index d6d50924b257..6d5305f5b330 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java @@ -172,27 +172,28 @@ class EditorCoordinateMapper { int maxLogicalColumn = 0; int maxOffset = offset; LogicalPosition delayedResult = null; + boolean delayedInlay = false; for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) { - if (delayedResult != null) return delayedResult.leanForward(fragment.getCurrentInlay() == null); int minColumn = fragment.getStartVisualColumn(); int maxColumn = fragment.getEndVisualColumn(); + if (delayedResult != null && minColumn != maxColumn) { + return delayedInlay ? delayedResult.leanForward(fragment.getCurrentInlay() == null) : delayedResult; + } if (column < minColumn || column == minColumn && !pos.leansRight && minColumn != maxColumn) { return offsetToLogicalPosition(offset); } if (column > minColumn && column < maxColumn || column == minColumn || column == maxColumn && !pos.leansRight) { - if (column == maxColumn && fragment.getCurrentInlay() != null) { - // for visual positions between adjacent inlays, we return same result as for visual position before the first one - delayedResult = new LogicalPosition(fragment.getEndLogicalLine(), fragment.getEndLogicalColumn(), true); - } - else { - return new LogicalPosition(column == maxColumn && (minColumn != maxColumn || fragment.getStartOffset() == 0) - ? fragment.getEndLogicalLine() : fragment.getStartLogicalLine(), - fragment.visualToLogicalColumn(column), - fragment.isCollapsedFoldRegion() ? column < maxColumn || minColumn == maxColumn : - fragment.getCurrentInlay() == null && fragment.isRtl() ^ pos.leansRight); - } + // for visual positions between adjacent inlays, we return same result as for visual position before the first one + delayedInlay = fragment.getCurrentInlay() != null; + delayedResult = + new LogicalPosition(column == maxColumn ? fragment.getEndLogicalLine() : fragment.getStartLogicalLine(), + fragment.visualToLogicalColumn(column), + fragment.isCollapsedFoldRegion() ? column < maxColumn : + !delayedInlay && fragment.isRtl() ^ pos.leansRight); + // delaying result to check whether there's an 'invisible' fold region going next + if (column != maxColumn) return delayedResult; } maxLogicalColumn = logicalLine == fragment.getEndLogicalLine() ? Math.max(maxLogicalColumn, fragment.getMaxLogicalColumn()) : fragment.getMaxLogicalColumn(); @@ -200,6 +201,7 @@ class EditorCoordinateMapper { logicalLine = fragment.getEndLogicalLine(); maxOffset = Math.max(maxOffset, fragment.getMaxOffset()); } + if (delayedResult != null && !delayedInlay) return delayedResult; if (myView.getEditor().getSoftWrapModel().getSoftWrap(maxOffset) == null) { boolean[] leansForward = new boolean[] {pos.leansRight}; int resultColumn = maxLogicalColumn + visToLogWithInlays(logicalLine, column - maxVisualColumn, leansForward); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java index df53349a783c..0366c3a31b23 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java @@ -349,7 +349,7 @@ public class EditorPainter implements TextDrawingCallback { boolean dryRun = visualLine > myEndVisualLine; if (dryRun && !calculateMarginWidths) break; boolean paintSoftWraps = paintAllSoftWraps || - myEditor.getCaretModel().getLogicalPosition().line == visLinesIterator.getStartLogicalLine(); + myEditor.getCaretModel().getLogicalPosition().line == visLinesIterator.getDisplayedLogicalLine(); int[] currentLogicalLine = new int[]{-1}; paintLineFragments(visLinesIterator, y, new LineFragmentPainter() { @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLineFragmentsIterator.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLineFragmentsIterator.java index 4cd0477919c9..2be5e3289d18 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLineFragmentsIterator.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLineFragmentsIterator.java @@ -348,8 +348,7 @@ class VisualLineFragmentsIterator implements Iterator 0 || myFoldRegion.getStartOffset() == 0) - ? getEndLogicalColumn(): getStartLogicalColumn() + ? column == myCurrentVisualColumn ? getEndLogicalColumn(): getStartLogicalColumn() : getEndLogicalColumn(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLinesIterator.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLinesIterator.java index 71cd8bb72640..a90ffa4090fd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLinesIterator.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/VisualLinesIterator.java @@ -87,6 +87,18 @@ public class VisualLinesIterator { myNextLocation.offset; } + public int getDisplayedLogicalLine() { + checkEnd(); + int foldIndex = myLocation.foldRegion; + if (foldIndex < myFoldRegions.length) { + FoldRegion foldRegion = myFoldRegions[foldIndex]; + if (foldRegion.getPlaceholderText().isEmpty() && foldRegion.getStartOffset() == myLocation.offset) { + return myDocument.getLineNumber(foldRegion.getEndOffset()); + } + } + return myLocation.logicalLine - 1; + } + public int getStartLogicalLine() { checkEnd(); return myLocation.logicalLine - 1; diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java index 09bda9a29b32..58a6403a2236 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java @@ -628,8 +628,8 @@ public class EditorImplTest extends AbstractEditorTest { addCollapsedFoldRegion(1, 2, ""); right(); Caret caret = getEditor().getCaretModel().getPrimaryCaret(); - assertEquals(1, caret.getOffset()); - assertEquals(new LogicalPosition(0, 1), caret.getLogicalPosition()); + assertEquals(2, caret.getOffset()); + assertEquals(new LogicalPosition(0, 2), caret.getLogicalPosition()); assertEquals(new VisualPosition(0, 1), caret.getVisualPosition()); right(); assertEquals(3, caret.getOffset());