/// <summary> /// Initiates processing of pending changes synchronously. /// </summary> internal void ProcessChanges() { if (this.IsDirty) { TreeUpdateTask.ProcessPendingTextBufferChanges(false); } }
protected virtual void Dispose(bool disposing) { if (disposing) { if (TextBuffer != null) { if (Closing != null) { Closing(this, null); } if (TreeUpdateTask != null) { TreeUpdateTask.Dispose(); TreeUpdateTask = null; } if (TreeLock != null) { TreeLock.Dispose(); TreeLock = null; } TextBuffer.ChangedHighPriority -= OnTextBufferChanged; TextBuffer = null; } } }
/// <summary> /// Builds initial AST. Subsequent updates should be coming from a background thread. /// </summary> public void Build() { if (_ownerThread != Thread.CurrentThread.ManagedThreadId) { throw new ThreadStateException("Method should only be called on the main thread"); } var sw = Stopwatch.StartNew(); TreeUpdateTask.Cancel(); if (TextBuffer != null) { TextSnapshot = TextBuffer.CurrentSnapshot; _astRoot = RParser.Parse(new TextProvider(TextBuffer.CurrentSnapshot)); } TreeUpdateTask.ClearChanges(); // Fire UpdatesPending notification, even though we don't have ranges for the event List <TextChangeEventArgs> textChanges = new List <TextChangeEventArgs>(); FireOnUpdatesPending(textChanges); FireOnUpdateBegin(); FireOnUpdateCompleted(TreeUpdateType.NewTree); sw.Stop(); }
/// <summary> /// Creates document tree on a given text buffer. /// </summary> /// <param name="textBuffer">Text buffer</param> public EditorTree(ITextBuffer textBuffer) { _ownerThread = Thread.CurrentThread.ManagedThreadId; TextBuffer = textBuffer; TextBuffer.ChangedHighPriority += OnTextBufferChanged; TreeUpdateTask = new TreeUpdateTask(this); TreeLock = new EditorTreeLock(); }
/// <summary> /// Creates document tree on a given text buffer. /// </summary> /// <param name="textBuffer">Text buffer</param> /// <param name="shell"></param> public EditorTree(ITextBuffer textBuffer, ICoreShell shell, IExpressionTermFilter filter = null) { _ownerThread = Thread.CurrentThread.ManagedThreadId; ExpressionTermFilter = filter; TextBuffer = textBuffer; TextBuffer.ChangedHighPriority += OnTextBufferChanged; TreeUpdateTask = new TreeUpdateTask(this, shell); TreeLock = new EditorTreeLock(); }
/// <summary> /// Initiates processing of pending changes asynchronously. When processing /// completes, tree will invoke completion callback on UI thread. Useful when building /// completion/intellisense list asynchronously. /// </summary> public void ProcessChangesAsync(Action treeUpdateCompleteCallback) { if (this.IsDirty) { TreeUpdateTask.RegisterCompletionCallback(treeUpdateCompleteCallback); TreeUpdateTask.ProcessPendingTextBufferChanges(true); } else { treeUpdateCompleteCallback.Invoke(); } }
/// <summary> /// Ensures tree is up to date, matches current text buffer snapshot /// and all changes since the last update were processed. Blocks until /// all changes have been processed. Does not pump messages. /// </summary> public void EnsureTreeReady() { if (TreeUpdateTask == null) { return; } if (_ownerThread != Thread.CurrentThread.ManagedThreadId) { throw new ThreadStateException("Method should only be called on the main thread"); } // OK to run in sync if changes are pending since we need it updated now TreeUpdateTask.EnsureProcessingComplete(); }
private void OnTextBufferChanged(object sender, TextContentChangedEventArgs e) { if (e.Changes.Count > 0) { // In case of tabbing multiple lines update comes as multiple changes // each is an insertion of whitespace in the beginning of the line. // We don't want to combine them since then change will technically // damage existing elements while actually it is just a whitespace change. // All changes are relative to the current snapshot hence we have to transform // them first and make them relative to each other so we can apply changes // sequentially as after every change element positions will shift and hence // next change must be relative to the new position and not to the current // text buffer snapshot. Changes are sorted by position. TreeUpdateTask.OnTextChanges(e.ConvertToRelative()); } }
/// <summary> /// Provides a way to automatically invoke particular action /// once when tree becomes ready again. Typically used in /// asynchronous completion and signature help scenarios. /// </summary> /// <param name="action">Action to invoke</param> /// <param name="p">Parameter to pass to the action</param> /// <param name="type">Action identifier</param> /// <param name="processNow"> /// If true, change processing begins now. /// If false, next regular parsing pass with process pending changes. /// </param> public void InvokeWhenReady(Action <object> action, object p, Type type, bool processNow = false) { if (IsReady) { action(p); } else { _actionsToInvokeOnReady[type] = new TreeReadyAction() { Action = action, Parameter = p }; if (processNow) { TreeUpdateTask.ProcessPendingTextBufferChanges(async: true); } } }
/// <summary> /// Makes current thread owner of the tree. /// Normally only one thread can access the tree. /// </summary> internal void TakeThreadOwnerShip() { _ownerThread = Thread.CurrentThread.ManagedThreadId; TreeUpdateTask.TakeThreadOwnership(); TreeLock.TakeThreadOwnership(); }