/// <summary>
/// Applies queued changes to the tree. Must only be called in a main thread context.
/// </summary>
/// <param name="o"></param>
internal void ApplyBackgroundProcessingResults()
{
if (_ownerThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new ThreadStateException("Method should only be called on the main thread");
}
if (_disposed)
{
return;
}
EditorTreeChangeCollection treeChanges;
var eventsToFire = new List <TreeChangeEventRecord>();
bool changed = false;
bool fullParse = false;
bool staleChanges = false;
while (_backgroundParsingResults.TryDequeue(out treeChanges))
{
// If no changes are pending, then main thread already processes
// everything in EnsureProcessingComplete call. Changes are pending
// until they are applied to the tree. If queue is not empty
// it either contains stale changes or main thread had to handle
// changes in sync per request from, say, intellisense or formatting.
if (ChangesPending)
{
// Check if background processing result matches current text buffer snapshot version
staleChanges = (TextBuffer != null && treeChanges.SnapshotVersion < TextBuffer.CurrentSnapshot.Version.VersionNumber);
if (!staleChanges)
{
// We can't fire events when appying changes since listeners may
// attempt to access tree which is not fully updated and/or may
// try to acquire read lock and hang since ApplyTreeChanges
// hols write lock.
eventsToFire = ApplyTreeChanges(treeChanges);
fullParse = _pendingChanges.FullParseRequired;
// Queue must be empty by now since only most recent changes are not stale
// Added local variable as I hit this assert, but _backgroundParsingResults.Count was zero
// by the time I broke into the debugger. If this hits again, we may need to
// think through this code and whether we need to be protecting against concurrent access.
int count = _backgroundParsingResults.Count;
Debug.Assert(count == 0);
// Clear pending changes as we are done
ClearChanges();
changed = true;
// No need for further processing as queue must be empty
break;
}
}
}
if (!staleChanges)
{
// Now that tree is fully updated, fire events
if (_editorTree != null)
{
if (changed)
{
_editorTree.FirePostUpdateEvents(eventsToFire, fullParse);
DebugTree.VerifyTree(_editorTree);
}
if (!ChangesPending)
{
Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
}
}
}
}