Example #1
0
        /// <summary>
        /// Handles simple (safe) changes.
        /// </summary>
        private void ProcessSimpleChange(TextChangeContext context)
        {
            bool elementsRemoved = false;

            try {
                _editorTree.AcquireWriteLock();

                elementsRemoved = DeleteAndShiftElements(context);
                UpdateTreeTextSnapshot();

                // If no elements were invalidated and full parse is not required, clear pending changes
                if (!elementsRemoved)
                {
                    ClearChanges();
                }
            } finally {
                _editorTree.ReleaseWriteLock();
            }

            if (!elementsRemoved)
            {
                if (context.ChangedNode != null || context.PendingChanges.TextChangeType == TextChangeType.Trivial)
                {
                    _editorTree.FireOnPositionsOnlyChanged();
                }

                _editorTree.FireOnUpdateCompleted(TreeUpdateType.PositionsOnly);
            }
            else
            {
                _editorTree.FireOnUpdateCompleted(TreeUpdateType.NodesRemoved);
            }

            DebugTree.VerifyTree(_editorTree);
            Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
        }
Example #2
0
        /// <summary>
        /// Applies queued changes to the tree. Must only be called in a main thread context.
        /// </summary>
        /// <param name="o"></param>
        internal void ApplyBackgroundProcessingResults()
        {
            if (_ownerThreadId != Thread.CurrentThread.ManagedThreadId)
            {
                throw new ThreadStateException("Method should only be called on the main thread");
            }

            if (_disposed)
            {
                return;
            }

            EditorTreeChangeCollection treeChanges;
            var  eventsToFire = new List <TreeChangeEventRecord>();
            bool changed      = false;
            bool fullParse    = false;
            bool staleChanges = false;

            while (_backgroundParsingResults.TryDequeue(out treeChanges))
            {
                // If no changes are pending, then main thread already processes
                // everything in EnsureProcessingComplete call. Changes are pending
                // until they are applied to the tree. If queue is not empty
                // it either contains stale changes or main thread had to handle
                // changes in sync per request from, say, intellisense or formatting.
                if (ChangesPending)
                {
                    // Check if background processing result matches current text buffer snapshot version
                    staleChanges = (TextBuffer != null && treeChanges.SnapshotVersion < TextBuffer.CurrentSnapshot.Version.VersionNumber);

                    if (!staleChanges)
                    {
                        // We can't fire events when appying changes since listeners may
                        // attempt to access tree which is not fully updated and/or may
                        // try to acquire read lock and hang since ApplyTreeChanges
                        // hols write lock.

                        eventsToFire = ApplyTreeChanges(treeChanges);
                        fullParse    = _pendingChanges.FullParseRequired;

                        // Queue must be empty by now since only most recent changes are not stale
                        // Added local variable as I hit this assert, but _backgroundParsingResults.Count was zero
                        //   by the time I broke into the debugger. If this hits again, we may need to
                        //   think through this code and whether we need to be protecting against concurrent access.
                        int count = _backgroundParsingResults.Count;
                        Debug.Assert(count == 0);

                        // Clear pending changes as we are done
                        ClearChanges();

                        changed = true;

                        // No need for further processing as queue must be empty
                        break;
                    }
                }
            }

            if (!staleChanges)
            {
                // Now that tree is fully updated, fire events
                if (_editorTree != null)
                {
                    if (changed)
                    {
                        _editorTree.FirePostUpdateEvents(eventsToFire, fullParse);
                        DebugTree.VerifyTree(_editorTree);
                    }

                    if (!ChangesPending)
                    {
                        Debug.Assert(_editorTree.AstRoot.Children.Count > 0);
                    }
                }
            }
        }