From 325c9cf27e71fc38cb63a33b4b18ebca8a86c7d8 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 24 Apr 2020 15:44:38 +0300 Subject: [PATCH] follow-up to IDEA-235209 fix more consistent treatment of 'invisible' fold regions - always map their visual position to the end of the region (after the previous fix it was mapped to the start of all regions unless the region was located at the document beginning) GitOrigin-RevId: 77420dfce4ebcfdc7fd760d77904d119a91611e6 --- .../render/JavaDocRenderTest.java | 24 +++++++++++++---- .../documentation/render/DocRenderItem.java | 14 ++-------- .../openapi/editor/ex/util/EditorUtil.java | 20 ++------------ .../impl/EditorGutterComponentImpl.java | 9 ++----- .../impl/view/EditorCoordinateMapper.java | 26 ++++++++++--------- .../editor/impl/view/EditorPainter.java | 2 +- .../view/VisualLineFragmentsIterator.java | 3 +-- .../editor/impl/view/VisualLinesIterator.java | 12 +++++++++ .../openapi/editor/impl/EditorImplTest.java | 4 +-- 9 files changed, 55 insertions(+), 59 deletions(-) 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());