/// <summary>
/// Main asyncronous task body
/// </summary>
void ProcessTextChanges(TextChange changeToProcess, bool async, Func <bool> isCancelledCallback)
{
lock (_disposeLock) {
if (_editorTree == null || _disposed || isCancelledCallback())
{
return;
}
EditorTreeChangeCollection treeChanges = null;
// Cache id since it can change if task is canceled
long taskId = TaskId;
try {
AstRoot rootNode;
// We only need read lock since changes will be applied
// from the main thread
if (async)
{
rootNode = _editorTree.AcquireReadLock(_treeUserId);
}
else
{
rootNode = _editorTree.GetAstRootUnsafe();
}
treeChanges = new EditorTreeChangeCollection(changeToProcess.Version, changeToProcess.FullParseRequired);
TextChangeProcessor changeProcessor = new TextChangeProcessor(_editorTree, rootNode, isCancelledCallback);
bool fullParseRequired = changeToProcess.FullParseRequired;
if (fullParseRequired)
{
changeProcessor.FullParse(treeChanges, changeToProcess.NewTextProvider);
}
else
{
changeProcessor.ProcessChange(changeToProcess, treeChanges);
}
} finally {
if (async && _editorTree != null)
{
_editorTree.ReleaseReadLock(_treeUserId);
}
}
// Lock should be released at this point since actual application
// of tree changes is going to be happen from the main thread.
if (!isCancelledCallback() && treeChanges != null)
{
// Queue results for the main thread application. This must be done before
// signaling that the task is complete since if EnsureProcessingComplete
// is waiting it will want to apply changes itself rather than wait for
// the DispatchOnUIThread to go though and hence it will need all changes
// stored and ready for application.
_backgroundParsingResults.Enqueue(treeChanges);
}
// Signal task complete now so if main thread is waiting
// it can proceed and appy the changes immediately.
SignalTaskComplete(taskId);
if (_backgroundParsingResults.Count > 0)
{
_uiThreadTransitionRequestTime = DateTime.UtcNow;
// It is OK to post results while main thread might be working
// on them since if if it does, by the time posted request comes
// queue will already be empty.
if (async)
{
// Post request to apply tree changes to the main thread.
// This must NOT block or else task will never enter 'RanToCompletion' state.
EditorShell.DispatchOnUIThread(() => ApplyBackgroundProcessingResults());
}
else
{
// When processing is synchronous, apply changes and fire events right away.
ApplyBackgroundProcessingResults();
}
}
}
}