Microsoft.R.Editor.Tree.TextChangeProcessor.ProcessChange C# (CSharp) Method

ProcessChange() public method

Processes a single text change incrementally. Enqueues resulting tree changes in the supplied queue. Does not modify the tree. Changes are to be sent to the main thread and applied from there. Caller is responsible for the tree read lock acquisition.
public ProcessChange ( TextChange textChange, Microsoft.R.Editor.Tree.EditorTreeChangeCollection treeChanges ) : void
textChange TextChange
treeChanges Microsoft.R.Editor.Tree.EditorTreeChangeCollection Collection of tree changes to apply /// from the main thread
return void
        public void ProcessChange(TextChange textChange, EditorTreeChangeCollection treeChanges) {
            IAstNode startNode = null, endNode = null;
            PositionType startPositionType = PositionType.Undefined;
            PositionType endPositionType = PositionType.Undefined;
            IAstNode commonParent = null;

            int start = textChange.OldRange.Start;
            int oldLength = textChange.OldRange.Length;
            int newLength = textChange.NewRange.Length;
            int offset = newLength - oldLength;

            ITextProvider oldSnapshot = textChange.OldTextProvider;
            ITextProvider newSnapshot = textChange.NewTextProvider;

            // Find position type and the enclosing element node. Note that element 
            // positions have been adjusted already (it happens immediately in OnTextChange) 
            // so we should be looking at the new range even that tree hasn't 
            // been fully updated yet. For example,if we delete a node, subsequent 
            // elements were already shifted up and damaged nodes have been removed 
            // so current node positions reflect text buffer state after the change.

            _astRoot.GetElementsEnclosingRange(start, newLength, out startNode,
                          out startPositionType, out endNode, out endPositionType);

            if (startNode is AstRoot) {
                commonParent = _astRoot;
            } else if (startNode == endNode) {
                if (startPositionType == PositionType.Token) {
                    // Change in comment or string content. 
                    commonParent = OnTokenNodeChange(startNode as TokenNode, start, oldLength, newLength);
                }
            } else {
                //if (commonParent == null)
                //{
                //    // Find parent that still has well formed curly braces.
                //    commonParent = FindWellFormedOuterScope(startNode);
                //}

                if (commonParent == null) {
                    commonParent = _astRoot;
                }
            }

            if (IsCancellationRequested())
                return;

            if (!(commonParent is AstRoot)) {
                Debug.Assert(commonParent is IScope);
                AstRoot subTree = RParser.Parse(newSnapshot, commonParent, _editorTree.ExpressionTermFilter);
                return;
            }

            AstRoot newTree = RParser.Parse(newSnapshot, _editorTree.ExpressionTermFilter);
            treeChanges.ChangeQueue.Enqueue(new EditorTreeChange_NewTree(newTree));
        }

Usage Example

Example #1
0
        /// <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();
                    }
                }
            }
        }
All Usage Examples Of Microsoft.R.Editor.Tree.TextChangeProcessor::ProcessChange