mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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:
+12
-23
@@ -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;
|
||||
|
||||
+14
-31
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user