IDEA-57040 Soft wrap: IllegalArgumentException at SoftWrapDataMapper.adjustVisualPosition() on Folding/Collapse All action if there is nested foldable block

Document change events processing is corrected
This commit is contained in:
Denis Zhdanov
2010-08-03 16:20:20 +04:00
parent e2e759a0a3
commit 052d6eb71c
2 changed files with 26 additions and 54 deletions
@@ -28,25 +28,29 @@ import com.intellij.openapi.editor.event.DocumentListener;
*/
public abstract class LineOrientedDocumentChangeAdapter implements DocumentListener {
private enum ChangeType {
BEFORE, AFTER
}
@Override
public void beforeDocumentChange(DocumentEvent event) {
onChange(event, ChangeType.BEFORE);
Document document = event.getDocument();
int startLine = document.getLineNumber(normalize(event.getDocument(), event.getOffset()));
int endLine = document.getLineNumber(normalize(event.getDocument(), event.getOffset() + event.getOldLength()));
int symbolsDifference = event.getNewLength() - event.getOldLength();
beforeDocumentChange(startLine, endLine, symbolsDifference);
}
@Override
public void documentChanged(DocumentEvent event) {
onChange(event, ChangeType.AFTER);
Document document = event.getDocument();
int startLine = document.getLineNumber(normalize(event.getDocument(), event.getOffset()));
int endLine = document.getLineNumber(normalize(event.getDocument(), event.getOffset() + event.getNewLength()));
int symbolsDifference = event.getNewLength() - event.getOldLength();
afterDocumentChange(startLine, endLine, symbolsDifference);
}
/**
* Callback adapter method for {@link DocumentListener#beforeDocumentChange(DocumentEvent)} event.
*
* @param startLine first logical document line affected by the target event (inclusive)
* @param endLine last logical document line affected by the target event (inclusive)
* @param endLine old last logical document line affected by the target event (inclusive)
* @param symbolsDifference difference in number in symbols applied to the target document
*/
public abstract void beforeDocumentChange(int startLine, int endLine, int symbolsDifference);
@@ -55,26 +59,11 @@ public abstract class LineOrientedDocumentChangeAdapter implements DocumentListe
* Callback adapter method for {@link DocumentListener#documentChanged(DocumentEvent)} event.
*
* @param startLine first logical document line affected by the target event (inclusive)
* @param endLine last logical document line affected by the target event (inclusive)
* @param endLine new last logical document line affected by the target event (inclusive)
* @param symbolsDifference difference in number in symbols applied to the target document
*/
public abstract void afterDocumentChange(int startLine, int endLine, int symbolsDifference);
private void onChange(DocumentEvent event, ChangeType type) {
Document document = event.getDocument();
int startLine = document.getLineNumber(normalize(event.getDocument(), event.getOffset()));
int endLine = document.getLineNumber(
normalize(event.getDocument(), Math.max(event.getOffset() + event.getNewLength(), event.getOffset() + event.getOldLength()))
);
int symbolsDifference = event.getNewLength() - event.getOldLength();
switch (type) {
case AFTER: beforeDocumentChange(startLine, endLine, symbolsDifference); break;
case BEFORE: afterDocumentChange(startLine, endLine, symbolsDifference); break;
default: throw new IllegalStateException("Unsupported event change type: " + type);
}
}
private static int normalize(Document document, int offset) {
if (offset < 0) {
return 0;
@@ -32,16 +32,6 @@ import java.util.List;
*/
public class SoftWrapDocumentChangeManager {
/**
* Holds logical lines where soft wraps should be removed.
* <p/>
* The general idea is to do the following:
* <ul>
* <li>listen for document changes, mark all soft wraps that belong to modified logical line as <code>'dirty'</code>;</li>
* <li>remove soft wraps marked as 'dirty' on repaint;</li>
* </ul>
*/
private final TIntHashSet myDirtyLines = new TIntHashSet();
private final List<DeferredChange> myDeferredChanges = new ArrayList<DeferredChange>();
private final SoftWrapsStorage myStorage;
@@ -76,20 +66,19 @@ public class SoftWrapDocumentChangeManager {
// Update offsets for soft wraps that remain after the changed line(s).
List<TextChangeImpl> softWraps = myStorage.getSoftWraps();
for (DeferredChange change : myDeferredChanges) {
if (change.startLine >= document.getLineCount()) {
if (change.startOffset >= document.getTextLength()) {
continue;
}
int index = myStorage.getSoftWrapIndex(document.getLineStartOffset(change.startLine));
int index = myStorage.getSoftWrapIndex(change.startOffset);
if (index < 0) {
index = -index -1;
}
for (int i = index; i < softWraps.size(); i++) {
TextChangeImpl softWrap = softWraps.get(i);
if (softWrap.getStart() >= document.getTextLength()) {
if (softWrapsToRemoveIndices.contains(i)) {
continue;
}
int softWrapLine = document.getLineNumber(softWrap.getStart());
if (myDirtyLines.contains(softWrapLine)) {
if (softWrap.getStart() < change.endOffset || softWrap.getStart() >= document.getTextLength()) {
softWrapsToRemoveIndices.add(i);
continue;
}
@@ -106,44 +95,38 @@ public class SoftWrapDocumentChangeManager {
}
});
myDirtyLines.clear();
myDeferredChanges.clear();
}
private void init(Document document) {
private void init(final Document document) {
document.addDocumentListener(new LineOrientedDocumentChangeAdapter() {
@Override
public void beforeDocumentChange(int startLine, int endLine, int symbolsDifference) {
myDeferredChanges.add(
new DeferredChange(document.getLineStartOffset(startLine), document.getLineEndOffset(endLine), symbolsDifference)
);
}
@Override
public void afterDocumentChange(int startLine, int endLine, int symbolsDifference) {
updateDeferredData(startLine, endLine, symbolsDifference);
}
});
}
private void updateDeferredData(int startLine, int endLine, int symbolsDifference) {
for (int i = startLine; i <= endLine; i++) {
myDirtyLines.add(i);
}
myDeferredChanges.add(new DeferredChange(startLine, endLine, symbolsDifference));
}
private static class DeferredChange {
final int startLine;
final int endLine;
final int startOffset;
final int endOffset;
final int symbolsDifference;
DeferredChange(int startLine, int endLine, int symbolsDifference) {
this.startLine = startLine;
this.endLine = endLine;
DeferredChange(int startOffset, int endOffset, int symbolsDifference) {
this.startOffset = startOffset;
this.endOffset = endOffset;
this.symbolsDifference = symbolsDifference;
}
@Override
public String toString() {
return startLine + "-" + endLine + ": " + symbolsDifference;
return startOffset + "-" + endOffset + ": " + symbolsDifference;
}
}
}