don't invoke coordinate transformation functions while soft wrap model is in inconsistent state

This commit is contained in:
Dmitry Batrak
2015-11-06 11:28:54 +03:00
parent ac5f1e43b1
commit 01d5262bbf
3 changed files with 60 additions and 17 deletions
@@ -16,11 +16,11 @@
package com.intellij.openapi.editor.impl.softwrap.mapping;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.editor.impl.SoftWrapModelImpl;
import org.jetbrains.annotations.NotNull;
/**
@@ -55,15 +55,15 @@ public class IncrementalCacheUpdateEvent {
* @param event object that describes document change that caused cache update
*/
IncrementalCacheUpdateEvent(@NotNull DocumentEvent event, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) {
this(event.getDocument(), event.getOffset(), event.getOffset() + event.getOldLength(), event.getOffset() + event.getNewLength(), mapper, editor);
this(event.getOffset(), event.getOffset() + event.getOldLength(), event.getOffset() + event.getNewLength(), mapper, editor);
}
/**
* Creates new <code>IncrementalCacheUpdateEvent</code> object for the event not changing document length
* (like expansion of folded region).
*/
IncrementalCacheUpdateEvent(@NotNull Document document, int startOffset, int endOffset, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) {
this(document, startOffset, endOffset, endOffset, mapper, editor);
IncrementalCacheUpdateEvent(int startOffset, int endOffset, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) {
this(startOffset, endOffset, endOffset, mapper, editor);
myNewEndLogicalLine = myOldEndLogicalLine;
}
@@ -82,22 +82,59 @@ public class IncrementalCacheUpdateEvent {
myOldEndLogicalLine = myNewEndLogicalLine = Math.max(0, document.getLineCount() - 1);
}
private IncrementalCacheUpdateEvent(@NotNull Document document, int startOffset, int oldEndOffset, int newEndOffset,
private IncrementalCacheUpdateEvent(int startOffset, int oldEndOffset, int newEndOffset,
@NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) {
myStartOffset = editor.myUseNewRendering ? editor.visualLineStartOffset(editor.offsetToVisualLine(startOffset) - 1) :
mapper.getPreviousVisualLineStartOffset(startOffset);
myMandatoryEndOffset = newEndOffset;
myLengthDiff = newEndOffset - oldEndOffset;
myStartLogicalPosition = editor.myUseNewRendering ? editor.offsetToLogicalPosition(myStartOffset) :
mapper.offsetToLogicalPosition(myStartOffset);
if (editor.myUseNewRendering) {
myStartVisualPosition = editor.logicalToVisualPosition(myStartLogicalPosition);
VisualLineInfo info = getVisualLineInfo(editor, startOffset, false);
if (info.startsWithSoftWrap) {
info = getVisualLineInfo(editor, info.startOffset, true);
}
myStartOffset = info.startOffset;
myStartLogicalPosition = editor.offsetToLogicalPosition(myStartOffset);
myStartVisualPosition = new VisualPosition(info.visualLine, 0);
}
else {
myStartOffset = mapper.getPreviousVisualLineStartOffset(startOffset);
myStartLogicalPosition = mapper.offsetToLogicalPosition(myStartOffset);
LOG.assertTrue(myStartLogicalPosition.visualPositionAware);
myStartVisualPosition = myStartLogicalPosition.toVisualPosition();
}
myOldEndLogicalLine = document.getLineNumber(oldEndOffset);
myMandatoryEndOffset = newEndOffset;
myLengthDiff = newEndOffset - oldEndOffset;
myOldEndLogicalLine = editor.getDocument().getLineNumber(oldEndOffset);
}
private static VisualLineInfo getVisualLineInfo(@NotNull EditorImpl editor, int offset, boolean beforeSoftWrap) {
Document document = editor.getDocument();
int textLength = document.getTextLength();
if (offset <= 0 || textLength == 0) return new VisualLineInfo(0, 0, false);
offset = Math.min(offset, textLength);
int startOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset);
SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel();
int wrapIndex = softWrapModel.getSoftWrapIndex(offset);
int prevSoftWrapIndex = wrapIndex < 0 ? (- wrapIndex - 2) : wrapIndex - (beforeSoftWrap ? 1 : 0);
SoftWrap prevSoftWrap = prevSoftWrapIndex < 0 ? null : softWrapModel.getRegisteredSoftWraps().get(prevSoftWrapIndex);
int visualLine = document.getLineNumber(offset) - editor.getFoldingModel().getFoldedLinesCountBefore(offset) + (prevSoftWrapIndex + 1);
int visualLineStartOffset = prevSoftWrap == null ? startOffset : Math.max(startOffset, prevSoftWrap.getStart());
return new VisualLineInfo(visualLine,
visualLineStartOffset,
prevSoftWrap != null && prevSoftWrap.getStart() == visualLineStartOffset);
}
private static class VisualLineInfo {
private final int visualLine;
private final int startOffset;
private final boolean startsWithSoftWrap;
private VisualLineInfo(int visualLine, int startOffset, boolean wrap) {
this.visualLine = visualLine;
this.startOffset = startOffset;
startsWithSoftWrap = wrap;
}
}
public void updateAfterDocumentChange(@NotNull Document document) {
@@ -193,8 +193,7 @@ public class SoftWrapApplianceManager implements Dumpable {
for (Segment range : ranges) {
int lastOffset = lastRecalculatedOffset[0];
if (range.getEndOffset() > lastOffset) {
recalculateSoftWraps(new IncrementalCacheUpdateEvent(myEditor.getDocument(),
Math.max(range.getStartOffset(), lastOffset), range.getEndOffset(),
recalculateSoftWraps(new IncrementalCacheUpdateEvent(Math.max(range.getStartOffset(), lastOffset), range.getEndOffset(),
myDataMapper, myEditor));
}
}
@@ -199,4 +199,11 @@ public class EditorImplTest extends AbstractEditorTest {
myEditor.getSettings().setAdditionalLinesCount(0);
assertEquals(new Dimension(50, 30), myEditor.getContentComponent().getPreferredSize());
}
public void testCollapsingRegionContainingSoftWrap() throws Exception {
initText("abcdef abcdef");
configureSoftWraps(10);
addCollapsedFoldRegion(0, 13, "...");
assertEquals(new VisualPosition(0, 3), myEditor.offsetToVisualPosition(13));
}
}