internal void EnsureProcessingComplete() {
if (_ownerThreadId != Thread.CurrentThread.ManagedThreadId)
throw new ThreadStateException("Method should only be called on the main thread");
// We want to make sure changes that are in a background processing are applied to the tree
// before returning. We can't wait on events since call comes on a main thread and wait
// will prevent WPF dispatcher call from going through.
// this will attempt to apply changes from the background processing results queue.
// It will discard stale changes and only apply changes if they match current
// text buffer snapshot version. This will only apply changes are that already
// in the queue. If background task is still running or all changes are stale
// the tree still will be out of date.
// Check if tree is up to date. It is up to date if there are no text buffer changes that
// are pending for background processing.
if (ChangesPending) {
// If task is running, give it a chance to finish. No need to wait long
// since even on a large file full parse rarely takes more than 50 ms.
// Also we can't wait indefinitely since if task is *scheduled to run*
// and then got cancelled before actually sarting, it will never complete.
WaitForCompletion(2000);
_uiThreadTransitionRequestTime = DateTime.UtcNow;
ApplyBackgroundProcessingResults();
if (ChangesPending) {
#if DEBUG
string originalPendingChanges = Changes.ToString();
#endif
// We *sometimes* still have pending changes even after calling ProcessPendingTextBufferChanges(async: false).
// I'd like to determine whether this is a timing issue by retrying here multiple times and seeing if it helps.
int retryCount = 0;
while (retryCount < 10 && ChangesPending) {
// Changes are still pending. Even if they are already in a backround processing,
// process them right away here and ignore background processing results
ProcessPendingTextBufferChanges(async: false);
retryCount += 1;
}
#if DEBUG
if (retryCount == 10) {
string msg = string.Format(CultureInfo.InvariantCulture,
"Pending changes remain: ChangesPending: {0}, original:\"{1}\", new:\"{2}\"",
ChangesPending, originalPendingChanges, Changes.ToString());
// using Debugger.Break as I want all threads suspended so the state doesn't change
Debug.Assert(false, msg);
}
#endif
}
}
Debug.Assert(!ChangesPending);
Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
}