public TextChangeContext(EditorTree editorTree, TextChangeEventArgs change, TextChange pendingChanges) { EditorTree = editorTree; NewStart = change.Start; OldStart = change.OldStart; OldLength = change.OldLength; NewLength = change.NewLength; OldTextProvider = change.OldText != null ? change.OldText : editorTree.AstRoot.TextProvider; NewTextProvider = change.NewText != null ? change.NewText : new TextProvider(editorTree.TextBuffer.CurrentSnapshot, partial: true); PendingChanges = pendingChanges; TextChange textChange = new TextChange(); textChange.OldRange = this.OldRange; textChange.OldTextProvider = this.OldTextProvider; textChange.NewRange = this.NewRange; textChange.NewTextProvider = this.NewTextProvider; textChange.Version = this.NewTextProvider.Version; PendingChanges.Combine(textChange); }
/// <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); }
/// <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 all elements from the tree _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); }