Example #1
0
        /// <summary>
        /// Combines one text change with another
        /// </summary>
        public void Combine(TreeTextChange other)
        {
            TextChangeType     = MathExtensions.Max(TextChangeType, other.TextChangeType);
            FullParseRequired |= other.FullParseRequired || TextChangeType == TextChangeType.Structure;

            // Combine two sequential changes into one. Note that damaged regions
            // typically don't shrink. There are some exceptions such as when
            // text was added and then deleted making the change effectively a no-op,
            // but this is not a typical case. For simplicity and fidelity
            // we'd rather parse more than less.

            if (FullParseRequired)
            {
                Start     = 0;
                OldLength = OldTextProvider?.Length ?? 0;
                NewLength = NewTextProvider?.Length ?? 0;
                return;
            }

            var oldEnd = Math.Max(OldEnd, other.OldEnd);
            var newEnd = Math.Max(NewEnd, other.NewEnd);

            Start = OldTextProvider != null?Math.Min(this.Start, other.Start) : other.Start;

            NewLength = Math.Max(newEnd, other.NewEnd) - Start;
            OldLength = Math.Max(oldEnd, other.OldEnd) - Start;

            Debug.Assert(OldLength >= 0);
            Debug.Assert(NewLength >= 0);
            Debug.Assert(Start <= OldEnd);
            Debug.Assert(Start <= NewEnd);

            if (OldTextProvider == null)
            {
                OldTextProvider = other.OldTextProvider;
            }
            else
            {
                OldTextProvider = other.OldTextProvider.Version < OldTextProvider.Version ? other.OldTextProvider : OldTextProvider;
            }

            if (NewTextProvider == null)
            {
                NewTextProvider = other.NewTextProvider;
            }
            else
            {
                NewTextProvider = other.NewTextProvider.Version > NewTextProvider.Version ? other.NewTextProvider : NewTextProvider;
            }

            NewLength = Math.Min(NewLength, NewTextProvider.Length);
            OldLength = Math.Min(OldLength, OldTextProvider.Length);

            Version = NewTextProvider.Version;
        }
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
        public TextChangeContext(IREditorTree editorTree, TreeTextChange change, TreeTextChange pendingChanges)
        {
            EditorTree = editorTree;

            TreeTextChange ttc;

            if (change.OldTextProvider == null || change.NewTextProvider == null)
            {
                var oldTextProvider = change.OldTextProvider ?? editorTree.AstRoot.TextProvider;
                var newTextProvider = change.NewTextProvider ?? editorTree.AstRoot.TextProvider;
                ttc = new TreeTextChange(change.Start, change.OldLength, change.NewLength, oldTextProvider, newTextProvider);
            }
            else
            {
                ttc = change;
            }

            PendingChanges = pendingChanges;
            PendingChanges.Combine(ttc);
        }