mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-156978 LineSet should handle typing in large lines more efficiently
This commit is contained in:
@@ -24,8 +24,11 @@ package com.intellij.editor;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.impl.LineSet;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
public class LineSetIncrementalUpdateTest extends LightCodeInsightTestCase {
|
||||
@@ -124,4 +127,18 @@ public class LineSetIncrementalUpdateTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
}.execute().throwException();
|
||||
}
|
||||
|
||||
public void testTypingInLongLinePerformance() {
|
||||
String longLine = StringUtil.repeat("a ", 200000);
|
||||
PlatformTestUtil.startPerformanceTest("Document changes in a long line", 1000, () -> {
|
||||
Document document = EditorFactory.getInstance().createDocument("a\n" + longLine + "<caret>" + longLine + "\n");
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
int offset = i * 2 + longLine.length();
|
||||
assertEquals(1, document.getLineNumber(offset));
|
||||
document.insertString(offset, "b");
|
||||
}
|
||||
});
|
||||
}).cpuBound().assertTiming();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.intellij.openapi.editor.impl;
|
||||
import com.intellij.openapi.editor.ex.LineIterator;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.util.BitUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.text.MergingCharSequence;
|
||||
import gnu.trove.TByteArrayList;
|
||||
import gnu.trove.TIntArrayList;
|
||||
@@ -65,11 +66,44 @@ public class LineSet{
|
||||
}
|
||||
|
||||
@NotNull
|
||||
LineSet update(@NotNull CharSequence prevText, int _start, int _end, @NotNull CharSequence replacement, boolean wholeTextReplaced) {
|
||||
LineSet update(@NotNull CharSequence prevText, int start, int end, @NotNull CharSequence replacement, boolean wholeTextReplaced) {
|
||||
if (myLength == 0) {
|
||||
return createLineSet(replacement, !wholeTextReplaced);
|
||||
}
|
||||
|
||||
LineSet result = isSingleLineChange(prevText, start, end, replacement)
|
||||
? updateInsideOneLine(findLineIndex(start), replacement.length() - (end - start))
|
||||
: genericUpdate(prevText, start, end, replacement);
|
||||
|
||||
if (doTest) {
|
||||
MergingCharSequence newText = new MergingCharSequence(
|
||||
new MergingCharSequence(prevText.subSequence(0, start), replacement),
|
||||
prevText.subSequence(end, prevText.length()));
|
||||
result.checkEquals(createLineSet(newText));
|
||||
}
|
||||
return wholeTextReplaced ? result.clearModificationFlags() : result;
|
||||
}
|
||||
|
||||
private boolean isSingleLineChange(@NotNull CharSequence prevText, int start, int end, @NotNull CharSequence replacement) {
|
||||
if (start == 0 && end == myLength && replacement.length() == 0) return false;
|
||||
|
||||
int startLine = findLineIndex(start);
|
||||
return startLine == findLineIndex(end) && !CharArrayUtil.containLineBreaks(replacement) && !isLastEmptyLine(startLine);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LineSet updateInsideOneLine(int line, int lengthDelta) {
|
||||
int[] starts = myStarts.clone();
|
||||
for (int i = line + 1; i < starts.length; i++) {
|
||||
starts[i] += lengthDelta;
|
||||
}
|
||||
|
||||
byte[] flags = myFlags.clone();
|
||||
flags[line] |= MODIFIED_MASK;
|
||||
return new LineSet(starts, flags, myLength + lengthDelta);
|
||||
}
|
||||
|
||||
private LineSet genericUpdate(CharSequence prevText, int _start, int _end, CharSequence replacement) {
|
||||
int startOffset = _start;
|
||||
if (replacement.length() > 0 && replacement.charAt(0) == '\n' && startOffset > 0 && prevText.charAt(startOffset - 1) == '\r') {
|
||||
startOffset--;
|
||||
@@ -90,14 +124,7 @@ public class LineSet{
|
||||
prevText.subSequence(_end, endOffset));
|
||||
|
||||
LineSet patch = createLineSet(replacement, true);
|
||||
LineSet applied = applyPatch(startOffset, endOffset, startLine, endLine, patch);
|
||||
if (doTest) {
|
||||
final MergingCharSequence newText = new MergingCharSequence(
|
||||
new MergingCharSequence(prevText.subSequence(0, startOffset), replacement),
|
||||
prevText.subSequence(endOffset, prevText.length()));
|
||||
applied.checkEquals(createLineSet(newText));
|
||||
}
|
||||
return wholeTextReplaced ? applied.clearModificationFlags() : applied;
|
||||
return applyPatch(startOffset, endOffset, startLine, endLine, patch);
|
||||
}
|
||||
|
||||
private void checkEquals(@NotNull LineSet fresh) {
|
||||
|
||||
Reference in New Issue
Block a user