IDEA-148683 lst: update LST only after end of WriteAction

This commit is contained in:
Aleksey Pivovarov
2015-12-03 13:42:17 +03:00
parent deb3138dd0
commit 2cbc4f041c
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.ex;
import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.DiffUtil;
import com.intellij.openapi.application.Application; import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationAdapter;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.UndoConstants; import com.intellij.openapi.command.undo.UndoConstants;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
@@ -78,6 +79,7 @@ public class LineStatusTracker {
@NotNull private final VcsDirtyScopeManager myVcsDirtyScopeManager; @NotNull private final VcsDirtyScopeManager myVcsDirtyScopeManager;
@NotNull private final MyDocumentListener myDocumentListener; @NotNull private final MyDocumentListener myDocumentListener;
@NotNull private final ApplicationAdapter myApplicationListener;
@Nullable private RevisionPack myBaseRevisionNumber; @Nullable private RevisionPack myBaseRevisionNumber;
@@ -91,6 +93,8 @@ public class LineStatusTracker {
@NotNull private List<Range> myRanges; @NotNull private List<Range> myRanges;
@Nullable private DirtyRange myDirtyRange;
private LineStatusTracker(@NotNull final Document document, private LineStatusTracker(@NotNull final Document document,
@NotNull final Document vcsDocument, @NotNull final Document vcsDocument,
@NotNull final Project project, @NotNull final Project project,
@@ -108,6 +112,9 @@ public class LineStatusTracker {
myDocumentListener = new MyDocumentListener(); myDocumentListener = new MyDocumentListener();
myDocument.addDocumentListener(myDocumentListener); myDocument.addDocumentListener(myDocumentListener);
myApplicationListener = new MyApplicationListener();
ApplicationManager.getApplication().addApplicationListener(myApplicationListener);
myMode = mode; myMode = mode;
myRanges = new ArrayList<Range>(); myRanges = new ArrayList<Range>();
@@ -119,7 +126,7 @@ public class LineStatusTracker {
synchronized (myLock) { synchronized (myLock) {
try { try {
if (myReleased) return; if (myInitialized || myReleased) return;
if (myBaseRevisionNumber != null && myBaseRevisionNumber.contains(baseRevisionNumber)) return; if (myBaseRevisionNumber != null && myBaseRevisionNumber.contains(baseRevisionNumber)) return;
myBaseRevisionNumber = baseRevisionNumber; myBaseRevisionNumber = baseRevisionNumber;
@@ -141,7 +148,7 @@ public class LineStatusTracker {
myApplication.assertIsDispatchThread(); myApplication.assertIsDispatchThread();
synchronized (myLock) { synchronized (myLock) {
if (myReleased) return; if (!myInitialized || myReleased || myBulkUpdate) return;
destroyRanges(); destroyRanges();
try { try {
@@ -269,10 +276,17 @@ public class LineStatusTracker {
} }
} }
public boolean isValid() {
synchronized (myLock) {
return myInitialized && !myReleased && !myAnathemaThrown && !myBulkUpdate && !myDuringRollback && myDirtyRange == null;
}
}
public void release() { public void release() {
synchronized (myLock) { synchronized (myLock) {
myReleased = true; myReleased = true;
myDocument.removeDocumentListener(myDocumentListener); myDocument.removeDocumentListener(myDocumentListener);
ApplicationManager.getApplication().removeApplicationListener(myApplicationListener);
if (myApplication.isDispatchThread()) { if (myApplication.isDispatchThread()) {
destroyRanges(); destroyRanges();
@@ -384,11 +398,36 @@ public class LineStatusTracker {
}); });
} }
private class MyApplicationListener extends ApplicationAdapter {
@Override
public void writeActionFinished(Object action) {
synchronized (myLock) {
if (!myInitialized || myReleased || myBulkUpdate || myDuringRollback || myAnathemaThrown) return;
if (myDirtyRange != null) {
doUpdateRanges(myDirtyRange.line1, myDirtyRange.line2, myDirtyRange.lineShift, myDirtyRange.beforeTotalLines);
myDirtyRange = null;
}
}
}
}
private class MyDocumentListener extends DocumentAdapter { private class MyDocumentListener extends DocumentAdapter {
// We have 3 document versions: /*
// * VCS version * beforeWriteLock beforeChange Current
// * before change * | | |
// * after change * | | line1 |
* updatedLine1 +============+-------------+ newLine1
* | | |
* r.line1 +------------+ oldLine1 |
* | | |
* | old | |
* | dirty | |
* | | oldLine2 |
* r.line2 +------------+ ----+ newLine2
* | | / |
* updatedLine2 +============+-------- |
* line2
*/
private int myLine1; private int myLine1;
private int myLine2; private int myLine2;
@@ -399,8 +438,8 @@ public class LineStatusTracker {
myApplication.assertIsDispatchThread(); myApplication.assertIsDispatchThread();
synchronized (myLock) { synchronized (myLock) {
if (myReleased) return; if (!myInitialized || myReleased) return;
if (myBulkUpdate || myDuringRollback || myAnathemaThrown || !myInitialized) return; if (myBulkUpdate || myDuringRollback || myAnathemaThrown) return;
assert myDocument == e.getDocument(); assert myDocument == e.getDocument();
myLine1 = myDocument.getLineNumber(e.getOffset()); myLine1 = myDocument.getLineNumber(e.getOffset());
@@ -420,8 +459,8 @@ public class LineStatusTracker {
myApplication.assertIsDispatchThread(); myApplication.assertIsDispatchThread();
synchronized (myLock) { synchronized (myLock) {
if (myReleased) return; if (!myInitialized || myReleased) return;
if (myBulkUpdate || myDuringRollback || myAnathemaThrown || !myInitialized) return; if (myBulkUpdate || myDuringRollback || myAnathemaThrown) return;
assert myDocument == e.getDocument(); assert myDocument == e.getDocument();
int newLine1 = myLine1; int newLine1 = myLine1;
@@ -439,7 +478,18 @@ public class LineStatusTracker {
int line1 = fixed[0]; int line1 = fixed[0];
int line2 = fixed[1]; int line2 = fixed[1];
doUpdateRanges(line1, line2, linesShift, myBeforeTotalLines); if (myDirtyRange == null) {
myDirtyRange = new DirtyRange(line1, line2, linesShift, myBeforeTotalLines);
}
else {
int oldLine1 = myDirtyRange.line1;
int oldLine2 = myDirtyRange.line2 + myDirtyRange.lineShift;
int updatedLine1 = myDirtyRange.line1 - Math.max(oldLine1 - line1, 0);
int updatedLine2 = myDirtyRange.line2 + Math.max(line2 - oldLine2, 0);
myDirtyRange = new DirtyRange(updatedLine1, updatedLine2, linesShift + myDirtyRange.lineShift, myDirtyRange.beforeTotalLines);
}
} }
} }
} }
@@ -545,8 +595,8 @@ public class LineStatusTracker {
catch (ProcessCanceledException ignore) { catch (ProcessCanceledException ignore) {
} }
catch (FilesTooBigForDiffException e1) { catch (FilesTooBigForDiffException e1) {
destroyRanges();
installAnathema(); installAnathema();
removeHighlightersFromMarkupModel();
} }
} }
@@ -803,7 +853,7 @@ public class LineStatusTracker {
myApplication.assertWriteAccessAllowed(); myApplication.assertWriteAccessAllowed();
synchronized (myLock) { synchronized (myLock) {
if (myReleased || myBulkUpdate || myDuringRollback || myAnathemaThrown) return; if (!isValid()) return;
try { try {
myDuringRollback = true; myDuringRollback = true;
@@ -909,6 +959,20 @@ public class LineStatusTracker {
} }
} }
private static class DirtyRange {
public final int line1;
public final int line2;
public final int lineShift;
public final int beforeTotalLines;
public DirtyRange(int line1, int line2, int lineShift, int beforeTotalLines) {
this.line1 = line1;
this.line2 = line2;
this.lineShift = lineShift;
this.beforeTotalLines = beforeTotalLines;
}
}
private static class CanNotCalculateDiffPanel extends EditorNotificationPanel { private static class CanNotCalculateDiffPanel extends EditorNotificationPanel {
public CanNotCalculateDiffPanel() { public CanNotCalculateDiffPanel() {
myLabel.setText("Can not highlight changed lines. File is too big and there are too many changes."); myLabel.setText("Can not highlight changed lines. File is too big and there are too many changes.");