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.
_shell.DispatchOnUIThread(ApplyBackgroundProcessingResults);
} else {
// When processing is synchronous, apply changes and fire events right away.
ApplyBackgroundProcessingResults();
}
}
}
}