diff --git a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index 1a4b1a68fb05..30cd08a7394c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -51,6 +51,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import javax.swing.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -127,19 +128,21 @@ public class DocumentCommitThread implements Runnable, Disposable { } public boolean queueCommit(@NonNls @NotNull String reason, @NotNull Document document, @NotNull Project project, @Nullable DocumentEvent event) { + log("queueCommit called", document, false, reason, event); assert !isDisposed : "already disposed"; if (!project.isInitialized()) return false; PsiFile psiFile = PsiDocumentManager.getInstance(project).getCachedPsiFile(document); if (psiFile == null) return false; - doQueue(document, project, getCommitStage(document), reason, event); - return true; + boolean added = doQueue(document, project, getCommitStage(document), reason, event); + log("doQueue called", document, false, added); + return added; } - private void doQueue(@NotNull Document document, @NotNull Project project, CommitStage start, @NonNls @NotNull String reason, @Nullable DocumentEvent event) { + private boolean doQueue(@NotNull Document document, @NotNull Project project, CommitStage start, @NonNls @NotNull String reason, @Nullable DocumentEvent event) { synchronized (documentsToCommit) { - if (!changeCommitStage(document, start, CommitStage.QUEUED_TO_COMMIT, false)) return; + if (!changeCommitStage(document, start, CommitStage.QUEUED_TO_COMMIT, false)) return false; Object[] documentTasks = documentsToCommit.toArray(); for (Object o : documentTasks) { @@ -148,28 +151,33 @@ public class DocumentCommitThread implements Runnable, Disposable { ProgressIndicator current = document.getUserData(COMMIT_PROGRESS); if (current == null) { // already queued, not started yet + return true; } else { - current.cancel(); // will be re-queued + // cancel current commit process to re-queue + current.cancel(); + removeCommitFromQueue(document); + break; } - return; } } ProgressIndicator indicator = new ProgressIndicatorBase(); indicator.start(); documentsToCommit.addLast(new CommitTask(document, project, indicator, reason, event)); log("Queued", document, false, reason); + return true; } } private final StringBuilder log = new StringBuilder(); - private void log(@NonNls String msg, Document document, boolean synchronously, @NonNls Object... args) { + void log(@NonNls String msg, Document document, boolean synchronously, @NonNls Object... args) { if (true) return; if (ApplicationManager.getApplication().isUnitTestMode()) { - String s = msg + (synchronously ? " (sync)" : "") + + String s = (SwingUtilities.isEventDispatchThread() ? " " : "") + + msg + (synchronously ? " (sync)" : "") + (document == null ? "" : "; Document: " + System.identityHashCode(document) + "; stage: " + getCommitStage(document)) - + "; my indic="+myProgressIndicator; + + "; my indic="+myProgressIndicator + " ||"; for (Object arg : args) { s += "; "+arg; @@ -204,11 +212,11 @@ public class DocumentCommitThread implements Runnable, Disposable { private static class CommitTask { private final Document document; private final Project project; + // running = false means document was removed from the queue, should ignore. + // canceled = true means commit was canceled, should reschedule for later. private final ProgressIndicator indicator; // progress to commit this doc under. private final String reason; @Nullable private final DocumentEvent event; - // running = false means document was removed from the queue, should ignore. - // canceled = true means commit was canceled, should reschedule for later. private CommitTask(@NotNull Document document, @NotNull Project project, @@ -261,8 +269,11 @@ public class DocumentCommitThread implements Runnable, Disposable { log("Pulled", document, false, indicator); - if (getCommitStage(document) != CommitStage.QUEUED_TO_COMMIT + CommitStage commitStage = getCommitStage(document); + if (commitStage != CommitStage.QUEUED_TO_COMMIT || project.isDisposed() || !ArrayUtil.contains(document,PsiDocumentManager.getInstance(project).getUncommittedDocuments())) { + log("Abandon and proceeding to next",document, false, commitStage, Arrays.asList( + PsiDocumentManager.getInstance(project).getUncommittedDocuments())); continue; } if (indicator.isRunning()) { @@ -279,7 +290,7 @@ public class DocumentCommitThread implements Runnable, Disposable { try { finishRunnable = commit(document, project, null, indicator, false, task.reason, task.event); success = finishRunnable != null; - log("Committed", document, false, finishRunnable, indicator); + log("DCT.commit returned", document, false, finishRunnable, indicator); } finally { document.putUserData(COMMIT_PROGRESS, null); @@ -292,9 +303,8 @@ public class DocumentCommitThread implements Runnable, Disposable { } if (success) { UIUtil.invokeLaterIfNeeded(finishRunnable); + log("Invoked later finishRunnable", document, false, success, finishRunnable, indicator); } - - log("Invoked later", document, false, success, finishRunnable, indicator); } } catch (ProcessCanceledException e) { @@ -313,8 +323,13 @@ public class DocumentCommitThread implements Runnable, Disposable { LOG.error(e); cancel(e); } - if (!success && indicator.isRunning()) { // running means sync commit has not intervened - doQueue(document, project, CommitStage.QUEUED_TO_COMMIT, "re-added on failure", null); + synchronized (documentsToCommit) { + if (!success && indicator.isRunning()) { // running means sync commit has not intervened + // reset status for queue back successfully + changeCommitStage(document, CommitStage.WAITING_FOR_PSI_APPLY, CommitStage.QUEUED_TO_COMMIT, false); + changeCommitStage(document, CommitStage.COMMITTED, CommitStage.QUEUED_TO_COMMIT, false); + doQueue(document, project, CommitStage.QUEUED_TO_COMMIT, "re-added on failure", null); + } } } catch(Throwable e) { @@ -344,8 +359,10 @@ public class DocumentCommitThread implements Runnable, Disposable { } ApplicationManager.getApplication().assertWriteAccessAllowed(); - setCommitStage(document, CommitStage.ABOUT_TO_BE_SYNC_COMMITTED, true); - removeCommitFromQueue(document); + synchronized (documentsToCommit) { + setCommitStage(document, CommitStage.ABOUT_TO_BE_SYNC_COMMITTED, true); + removeCommitFromQueue(document); + } ProgressIndicatorBase indicator = new ProgressIndicatorBase(); indicator.start(); @@ -463,14 +480,16 @@ public class DocumentCommitThread implements Runnable, Disposable { assert changed : "Before: " + before + "; after: " + getCommitStage(document); } } - if (synchronously) { - List unc = Arrays.asList(documentManager.getUncommittedDocuments()); + List unc = Arrays.asList(documentManager.getUncommittedDocuments()); + log("after call finish commit",document, synchronously, unc, success); + if (synchronously || success) { assert !unc.contains(document) : unc; } if (!success) { // add document back to the queue log("Re-adding back", document, synchronously, success, documentManager.isCommitted(document), Arrays.asList(documentManager.getUncommittedDocuments())); - queueCommit("Re-added back", document, project, null); + boolean addedBack = queueCommit("Re-added back", document, project, null); + assert addedBack; } } }); @@ -650,9 +669,9 @@ public class DocumentCommitThread implements Runnable, Disposable { } private boolean changeCommitStage(@NotNull Document document, - CommitStage expected, - @NotNull CommitStage stage, - boolean synchronously) { + CommitStage expected, + @NotNull CommitStage stage, + boolean synchronously) { boolean replaced = ((UserDataHolderEx)document).replace(COMMIT_STAGE, expected, stage); log("Changed stage", document, synchronously, expected, stage, replaced); return replaced; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index 98e0fb1410f6..623447567562 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -339,15 +339,15 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec } } finally { - //myDocumentCommitThread.log("in PDI.finishDoc: ",document, synchronously, success, myUncommittedDocuments); + myDocumentCommitThread.log("in PDI.finishDoc: ",document, synchronously, success, myUncommittedDocuments); if (success) { myUncommittedDocuments.remove(document); - //myDocumentCommitThread.log("in PDI.finishDoc: removed doc",document, synchronously, success, myUncommittedDocuments); + myDocumentCommitThread.log("in PDI.finishDoc: removed doc",document, synchronously, success, myUncommittedDocuments); ((DocumentImpl)document).normalizeRangeMarkers(); InjectedLanguageUtil.commitAllInjectedDocuments(document, myProject); } myIsCommitInProgress = false; - //myDocumentCommitThread.log("in PDI.finishDoc: exit",document, synchronously, success, myUncommittedDocuments); + myDocumentCommitThread.log("in PDI.finishDoc: exit",document, synchronously, success, myUncommittedDocuments); } if (success) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index bda7b5fdad29..91b60f6bfe18 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -825,16 +825,6 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } } - @Override - public String toString() { - StringBuilder buffer = new StringBuilder("document: "); - int linesNumber = getLineCount(); - for (int i = 0; i < linesNumber; i++) { - buffer.append(i).append(":").append(getLineStartOffset(i)).append("-").append(getLineEndOffset(i)).append(";"); - } - return buffer.toString(); - } - private static class MyCharArray extends CharArray { public MyCharArray() { super(0);