/// <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(); } } } }
/// <summary> /// Main asyncronous task body /// </summary> private void ProcessTextChange(IEditorBufferSnapshot snapshot, bool async, Func <bool> isCancelledCallback) { lock (_disposeLock) { if (_editorTree == null || _disposed || isCancelledCallback()) { return; } EditorTreeChangeCollection treeChanges; // Cache id since it can change if task is canceled var taskId = TaskId; try { // We only need read lock since changes will be applied from the main thread if (async) { _editorTree.AcquireReadLock(_treeUserId); } else { _editorTree.GetAstRootUnsafe(); } treeChanges = new EditorTreeChangeCollection(snapshot.Version, true); var newTree = RParser.Parse(snapshot, _editorTree.ExpressionTermFilter); treeChanges.Append(new EditorTreeChange_NewTree(newTree)); } finally { if (async) { _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.Changes.Any()) { // 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) { // 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. _services.MainThread().Post(ApplyBackgroundProcessingResults); } else { // When processing is synchronous, apply changes and fire events right away. ApplyBackgroundProcessingResults(); } } } }