InvalidateInRange() private method

Removes nodes from the tree collection if node range is partially or entirely within the deleted region. This is needed since parsing is asynchronous and without node removal intellisense and syntax checker may end up processing nodes that are out of date. Where possible stops at the nearest scope level so scope nodes may still be used in smart indenter.
private InvalidateInRange ( ITextRange range ) : bool
range ITextRange Range to invalidate elements in
return bool
Example #1
0
        /// <summary>
        /// Handles non-trivial changes like changes that delete elements,
        /// change identifier names, introducing new braces: changes
        /// that cannot be handled without background parse.
        /// </summary>
        private void ProcessComplexChange(TextChangeContext context)
        {
            // Cancel background parse if it is running
            Cancel();

            TextChange textChange = new TextChange()
            {
                OldTextProvider = context.OldTextProvider,
                NewTextProvider = context.NewTextProvider
            };

            try {
                // Get write lock since there may be concurrent readers
                // of the tree. Note that there are no concurrent writers
                // since changes can only come from a background parser
                // and are always applied from the main thread.
                _editorTree.AcquireWriteLock();

                if (_pendingChanges.FullParseRequired)
                {
                    // When full parse is required, change is like replace the entire file
                    textChange.OldRange = TextRange.FromBounds(0, context.OldText.Length);
                    textChange.NewRange = TextRange.FromBounds(0, context.NewText.Length);

                    // Remove damaged elements if any and reflect text change.
                    // Although we are invalidating the AST next, old copy will
                    // be kept for operations that may need it such as smart indent.
                    bool elementsChanged;
                    _editorTree.InvalidateInRange(_editorTree.AstRoot, context.OldRange, out elementsChanged);
                    _editorTree.NotifyTextChange(context.NewStart, context.OldLength, context.NewLength);
                    // Invalidate will store existing AST as previous snapshot
                    // and create temporary empty AST until the next async parse.
                    _editorTree.Invalidate();
                }
                else
                {
                    textChange.OldRange = context.OldRange;
                    textChange.NewRange = context.NewRange;

                    DeleteAndShiftElements(context);
                    Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
                }

                _pendingChanges.Combine(textChange);
                _pendingChanges.Version = TextBuffer != null ? TextBuffer.CurrentSnapshot.Version.VersionNumber : 1;

                UpdateTreeTextSnapshot();
            } finally {
                // Lock must be released before firing events otherwise we may hang
                _editorTree.ReleaseWriteLock();
            }

            _editorTree.FireOnUpdateCompleted(TreeUpdateType.NodesRemoved);
        }
Example #2
0
        /// <summary>
        /// Handles non-trivial changes like changes that delete elements,
        /// change identifier names, introducing new braces: changes
        /// that cannot be handled without background parse.
        /// </summary>
        private void ProcessComplexChange(TextChangeContext context)
        {
            // Cancel background parse if it is running
            Cancel();
            var c = context.PendingChanges;

            try {
                // Get write lock since there may be concurrent readers
                // of the tree. Note that there are no concurrent writers
                // since changes can only come from a background parser
                // and are always applied from the main thread.
                _editorTree.AcquireWriteLock();
                int start, oldLength, newLength;

                if (Changes.FullParseRequired)
                {
                    // When full parse is required, change is like replace the entire file
                    start     = 0;
                    oldLength = c.OldTextProvider.Length;
                    newLength = c.NewTextProvider.Length;

                    // Remove damaged elements if any and reflect text change.
                    // the tree remains usable outside of the damaged scope.
                    _editorTree.InvalidateInRange(c.OldRange);
                    _editorTree.NotifyTextChange(c.Start, c.OldLength, c.NewLength);
                }
                else
                {
                    start     = c.Start;
                    oldLength = c.OldLength;
                    newLength = c.NewLength;

                    DeleteAndShiftElements(context);
                    Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
                }

                var ttc = new TreeTextChange(start, oldLength, newLength, _editorTree.BufferSnapshot, EditorBuffer.CurrentSnapshot);
                Changes.Combine(ttc);
                Changes.Version = EditorBuffer?.CurrentSnapshot?.Version ?? 1;

                _editorTree.BufferSnapshot = EditorBuffer.CurrentSnapshot;
            } finally {
                // Lock must be released before firing events otherwise we may hang
                _editorTree.ReleaseWriteLock();
            }

            _editorTree.FireOnUpdateCompleted(TreeUpdateType.NodesRemoved);
        }
Example #3
0
        // internal for unit tests
        internal bool DeleteAndShiftElements(TextChangeContext context)
        {
            if (Thread.CurrentThread.ManagedThreadId != _ownerThreadId)
            {
                throw new ThreadStateException("Method should only be called on the main thread");
            }

            TextChange textChange      = context.PendingChanges;
            var        changeType      = textChange.TextChangeType;
            bool       elementsChanged = false;

            if (changeType == TextChangeType.Structure)
            {
                IAstNode changedElement = context.ChangedNode;
                int      start          = context.NewStart;

                // We delete change nodes unless node is a token node
                // which range can be modified such as string or comment
                var positionType = PositionType.Undefined;

                if (changedElement != null)
                {
                    IAstNode node;
                    positionType = changedElement.GetPositionNode(context.NewStart, out node);
                }

                bool deleteElements = (context.OldLength > 0) || (positionType != PositionType.Token);

                // In case of delete or replace we need to invalidate elements that were
                // damaged by the delete operation. We need to remove elements and their keys
                // so they won't be found by validator and incremental change analysis
                // will not be looking at zombies.

                if (deleteElements)
                {
                    _pendingChanges.FullParseRequired =
                        _editorTree.InvalidateInRange(_editorTree.AstRoot, context.OldRange, out elementsChanged);
                }
            }

            _editorTree.NotifyTextChange(context.NewStart, context.OldLength, context.NewLength);

            return(elementsChanged);
        }