public void ScheduleIndependentEdit(BaseProjectionBuffer projectionBuffer) { // A projection buffer has received a content change event from one of its source buffers, but // it has no edit in progress. This means it is an independent buffer (with respect to the master edit) // and needs to have its event propagation scheduled. this.pendingIndependentBuffers.Add(projectionBuffer); }
private bool IsStableDuringIndependentPhase(BaseBuffer sourceBuffer) { BaseProjectionBuffer baseProjSourceBuffer = sourceBuffer as BaseProjectionBuffer; if (baseProjSourceBuffer != null && this.pendingIndependentBuffers.Contains(baseProjSourceBuffer)) { return(false); } else { GraphEntry g; if (this.graph.TryGetValue(sourceBuffer, out g)) { return(g.Dependent || !InTargetClosureOfBuffer(sourceBuffer, this.masterBuffer)); } else { // must be a projection literal buffer return(true); } } }
public void CancelIndependentEdit(BaseProjectionBuffer projectionBuffer) { // A buffer that thought it was independent turned out not to be so. May be called by buffers // that are not in the pendingIndependentBuffers set. this.pendingIndependentBuffers.Remove(projectionBuffer); }
public void PerformMasterEdit(ITextBuffer buffer, ISubordinateTextEdit xedit, EditOptions options, object editTag) { Debug.Assert(this.MembersContains(buffer)); if (this.masterBuffer != null) { // internal error throw new InvalidOperationException("Master edit already in progress"); } try { this.masterBuffer = (BaseBuffer)buffer; this.masterOptions = options; this.masterEditTag = editTag; this.buffer2EditMap = new Dictionary <ITextBuffer, ISubordinateTextEdit>(); this.buffer2EditMap.Add(buffer, xedit); this.pendingIndependentBuffers = new HashSet <BaseProjectionBuffer>(); BuildGraph(); Trace(buffer, "Master"); Stack <ISubordinateTextEdit> appliedSubordinateEdits = new Stack <ISubordinateTextEdit>(); while (this.buffer2EditMap.Count > 0) { // Pick an edit that has no possibility of further impact from target projection buffers. ISubordinateTextEdit subedit = PickEdit(); Trace(subedit, "Pre Apply"); PopulateSourceEdits(subedit.TextBuffer); subedit.PreApply(); // this may add more edits to buffer2EditMap appliedSubordinateEdits.Push(subedit); } Action cancelAction = () => { foreach (var edit in appliedSubordinateEdits) { edit.CancelApplication(); } Debug.Assert(this.pendingIndependentBuffers.Count == 0); Debug.Assert(this.depth == 0); this.graph = null; this.buffer2EditMap = null; this.masterBuffer = null; this.pendingIndependentBuffers = null; }; foreach (var edit in appliedSubordinateEdits) { if (!edit.CheckForCancellation(cancelAction)) { Debug.Assert(this.graph == null); Debug.Assert(this.buffer2EditMap == null); Debug.Assert(this.masterBuffer == null); Debug.Assert(this.pendingIndependentBuffers == null); Debug.Assert(this.eventQueue.Count == 0); Debug.Assert(this.depth == 0); Debug.Assert(!this.eventingInProgress); return; } } // pendingIndependentBuffers currently do not get a voice in cancelation. // now interpret events in the reverse order while (appliedSubordinateEdits.Count > 0) { ISubordinateTextEdit subedit = appliedSubordinateEdits.Pop(); Trace(subedit.TextBuffer, "Final Apply"); subedit.FinalApply(); // this creates the snapshot and queues/raises events...TODO: make it return raisers } // move on to independent edits while (this.pendingIndependentBuffers.Count > 0) { BaseProjectionBuffer projectionBuffer = PickIndependentBuffer(); Trace(projectionBuffer, "Propagate"); BaseBuffer.ITextEventRaiser raiser = projectionBuffer.PropagateSourceChanges(options, editTag); this.eventQueue.Enqueue(new Tuple <BaseBuffer.ITextEventRaiser, BaseBuffer>(raiser, projectionBuffer)); } this.graph = null; this.buffer2EditMap = null; this.masterBuffer = null; this.pendingIndependentBuffers = null; } catch (Exception e) { BufferGroup.LastMasterEditException = e; BufferGroup.LastMasterEditExceptionStackTrace = e.StackTrace; throw; } }