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
This commit is contained in:
Dmitry Batrak
2020-04-24 13:02:19 +00:00
committed by intellij-monorepo-bot
parent 95838c56f4
commit 325c9cf27e
9 changed files with 55 additions and 59 deletions
@@ -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" +
"<caret> /** doc */\n" +
" int a;\n" +
" /** doc */\n" +
"<caret> int a;\n" +
"}\n");
}
public void testTypingAtLineStart() {
configure("class C {\n" +
"/** doc */\n" +
"int a;<caret>\n" +
"}\n", true);
verifyFoldingState("[FoldRegion +(10:21), placeholder='']");
executeAction(IdeActions.ACTION_EDITOR_MOVE_LINE_START);
type(' ');
checkResultByText("class C {\n" +
"/** doc */\n" +
" <caret>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");
}
@@ -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) {
@@ -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) {
@@ -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);
}
@@ -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);
@@ -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
@@ -348,8 +348,7 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
return myDelegate != null
? myDelegate.visualToLogicalColumn(column)
: myFoldRegion != null
? column == myCurrentVisualColumn && (myFoldRegionColumns > 0 || myFoldRegion.getStartOffset() == 0)
? getEndLogicalColumn(): getStartLogicalColumn()
? column == myCurrentVisualColumn ? getEndLogicalColumn(): getStartLogicalColumn()
: getEndLogicalColumn();
}
@@ -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;
@@ -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());