예제 #1
0
 /// <summary>
 /// Creates a ReadOnlyRegionHandle for the given buffer and span.
 /// </summary>
 /// <param name="version">
 /// The <see cref="TextVersion"/> with which this read only region is associated.
 /// </param>
 /// <param name="span">
 /// The span of interest.
 /// </param>
 /// <param name="trackingMode">
 /// Specifies the tracking behavior of the read only region.
 /// </param>
 /// <param name="edgeInsertionMode">
 /// Specifies if insertions should be allowed at the edges
 /// </param>
 /// <remarks>
 /// Don't call this constructor with invalid parameters.  It doesn't verify all of them.
 /// </remarks>
 internal ReadOnlyRegion(TextVersion version, Span span, SpanTrackingMode trackingMode, EdgeInsertionMode edgeInsertionMode, DynamicReadOnlyRegionQuery callback)
 {
     _edgeInsertionMode = edgeInsertionMode;
     // TODO: change to simple forward tracking text span
     _trackingSpan = new ForwardFidelityTrackingSpan(version, span, trackingMode);
     QueryCallback = callback;
 }
예제 #2
0
        internal TextContentChangedEventArgs ApplyReload(StringRebuilder newContent, EditOptions editOptions, object editTag)
        {
            // we construct a normalized change list where the inserted text is a reference string that
            // points "forward" to the next snapshot and whose deleted text is a reference string that points
            // "backward" to the prior snapshot. This pins both snapshots in memory but that's better than materializing
            // giant strings, and when (?) we have paging text storage, memory requirements will be minimal.
            TextVersion           newVersion  = new TextVersion(this, this.currentVersion.VersionNumber + 1, this.currentVersion.VersionNumber + 1, newContent.Length);
            ITextSnapshot         oldSnapshot = this.currentSnapshot;
            TextSnapshot          newSnapshot = new TextSnapshot(this, newVersion, newContent);
            ReferenceChangeString oldText     = new ReferenceChangeString(new SnapshotSpan(oldSnapshot, 0, oldSnapshot.Length));
            ReferenceChangeString newText     = new ReferenceChangeString(new SnapshotSpan(newSnapshot, 0, newSnapshot.Length));
            TextChange            change      = new TextChange(oldPosition: 0,
                                                               oldText: oldText,
                                                               newText: newText,
                                                               currentSnapshot: oldSnapshot);

            this.currentVersion.AddNextVersion(NormalizedTextChangeCollection.Create(new FrugalList <TextChange>()
            {
                change
            },
                                                                                     editOptions.ComputeMinimalChange
                                                                                         ? (StringDifferenceOptions?)editOptions.DifferenceOptions
                                                                                         : null,
                                                                                     this.textDifferencingService,
                                                                                     oldSnapshot, newSnapshot),
                                               newVersion);
            this.builder         = newContent;
            this.currentVersion  = newVersion;
            this.currentSnapshot = newSnapshot;
            return(new TextContentChangedEventArgs(oldSnapshot, newSnapshot, editOptions, editTag));
        }
예제 #3
0
        internal TextContentChangedEventArgs ApplyReload(StringRebuilder newContent, EditOptions editOptions, object editTag)
        {
            // we construct a normalized change list where the inserted text is a reference string that
            // points "forward" to the next snapshot and whose deleted text is a reference string that points
            // "backward" to the prior snapshot. This pins both snapshots in memory but that's better than materializing
            // giant strings, and when (?) we have paging text storage, memory requirements will be minimal.
            ITextSnapshot   oldSnapshot = this.currentSnapshot;
            StringRebuilder oldContent  = BufferFactoryService.StringRebuilderFromSnapshotSpan(new SnapshotSpan(oldSnapshot, 0, oldSnapshot.Length));

            TextChange change = TextChange.Create(oldPosition: 0,
                                                  oldText: oldContent,
                                                  newText: newContent,
                                                  currentSnapshot: oldSnapshot);


            TextVersion  newVersion  = this.currentVersion.CreateNext(changes: null, newLength: newContent.Length, reiteratedVersionNumber: -1);
            TextSnapshot newSnapshot = new TextSnapshot(this, newVersion, newContent);

            this.currentVersion.SetChanges(NormalizedTextChangeCollection.Create(new TextChange[] { change },
                                                                                 editOptions.ComputeMinimalChange
                                                                                 ? (StringDifferenceOptions?)editOptions.DifferenceOptions
                                                                                 : null,
                                                                                 this.textDifferencingService,
                                                                                 oldSnapshot, newSnapshot));


            this.currentVersion  = newVersion;
            this.builder         = newContent;
            this.currentSnapshot = newSnapshot;
            return(new TextContentChangedEventArgs(oldSnapshot, newSnapshot, editOptions, editTag));
        }
예제 #4
0
 public ForwardFidelityCustomTrackingSpan(TextVersion version, Span span, object customState, CustomTrackToVersion behavior)
     : base(version, span, SpanTrackingMode.Custom)
 {
     if (behavior == null)
     {
         throw new ArgumentNullException(nameof(behavior));
     }
     this.behavior    = behavior;
     this.customState = customState;
 }
예제 #5
0
        protected BaseBuffer(IContentType contentType, int initialLength, ITextDifferencingService textDifferencingService, GuardedOperations guardedOperations)
        {
            // parameters are validated outside
            Debug.Assert(contentType != null);

            this.contentType             = contentType;
            this.currentVersion          = new TextVersion(this, 0, 0, initialLength);
            this.textDifferencingService = textDifferencingService;
            this.guardedOperations       = guardedOperations;
        }
예제 #6
0
        protected BaseBuffer(IContentType contentType, int initialLength, ITextDifferencingService textDifferencingService, GuardedOperations guardedOperations)
        {
            // parameters are validated outside
            Debug.Assert(contentType != null);

            this.contentType    = contentType;
            this.currentVersion = new TextVersion(this, new TextImageVersion(initialLength));
            // this.builder should be set in calling ctor
            this.textDifferencingService = textDifferencingService;
            this.guardedOperations       = guardedOperations;
        }
예제 #7
0
        /// <summary>
        /// Attaches the change to the current node and creates the next version node
        /// </summary>
        public TextVersion CreateNext(INormalizedTextChangeCollection changes, int reiteratedVersionNumber)
        {
            this.normalizedChanges = changes;
            int delta       = 0;
            int changeCount = changes.Count;

            for (int c = 0; c < changeCount; ++c)
            {
                delta += changes[c].Delta;
            }
            this.next = new TextVersion(this.TextBuffer, this.VersionNumber + 1, reiteratedVersionNumber, this.versionLength + delta);
            return(this.next);
        }
예제 #8
0
        /// <summary>
        /// Create a new version based on applying <paramref name="changes"/> to this.
        /// </summary>
        /// <param name="changes">null if set later</param>
        /// <param name="newLength">use -1 to compute a length</param>
        /// <param name="reiteratedVersionNumber">use -1 to get the default value</param>
        /// <remarks>
        /// <para>If <paramref name="changes"/> can be null, then <paramref name="newLength"/> cannot be -1.</para>
        /// </remarks>
        internal TextVersion CreateNext(INormalizedTextChangeCollection changes, int newLength = -1, int reiteratedVersionNumber = -1)
        {
            if (this.Next != null)
            {
                throw new InvalidOperationException("Not allowed to CreateNext twice");
            }

            var newTextImageVersion = this._textImageVersion.CreateNext(reiteratedVersionNumber: reiteratedVersionNumber, length: newLength, changes: changes);

            var next = new TextVersion(this.TextBuffer, newTextImageVersion);

            this.Next = next;

            return(next);
        }
예제 #9
0
 /// <summary>
 /// Used when the normalized change list of a version needs to refer ahead to the following snapshot
 /// </summary>
 public void AddNextVersion(INormalizedTextChangeCollection changes, TextVersion nextVersion)
 {
     this.normalizedChanges = changes;
     this.next = nextVersion;
 }
예제 #10
0
 protected void SetCurrentVersionAndSnapshot(INormalizedTextChangeCollection normalizedChanges, int reiteratedVersionNumber = -1)
 {
     this.currentVersion  = this.currentVersion.CreateNext(normalizedChanges, newLength: -1, reiteratedVersionNumber: reiteratedVersionNumber);
     this.builder         = this.ApplyChangesToStringRebuilder(normalizedChanges, this.builder);
     this.currentSnapshot = TakeSnapshot();
 }
예제 #11
0
 protected void SetCurrentVersionAndSnapshot(INormalizedTextChangeCollection normalizedChanges)
 {
     this.currentVersion = this.currentVersion.CreateNext(normalizedChanges);
     UpdateSnapshot();
 }
예제 #12
0
 protected void SetCurrentVersionAndSnapshot(INormalizedTextChangeCollection normalizedChanges, int reiteratedVersionNumber)
 {
     this.currentVersion = this.currentVersion.CreateNext(normalizedChanges, reiteratedVersionNumber);
     UpdateSnapshot();
 }
 /// <summary>
 /// Construct a ReadOnlySpanCollection that contains everything in a list of spans.
 /// </summary>
 /// <param name="regions">ReadOnlyRegions</param>
 /// <param name="version">The version this span collection applies to.</param>
 /// <remarks>
 /// <para>The list of spans will be sorted and normalized (overlapping and adjoining spans will be combined).</para>
 /// </remarks>
 /// <exception cref="ArgumentNullException"><paramref name="regions"/> is null.</exception>
 internal ReadOnlySpanCollection(TextVersion version, IEnumerable <IReadOnlyRegion> regions)
     : base(NormalizeSpans(version, regions))
 {
     regionsWithActions = regions.Where(region => region.QueryCallback != null).ToList();
 }
        private static IList <ReadOnlySpan> NormalizeSpans(TextVersion version, IEnumerable <IReadOnlyRegion> regions)
        {
            List <IReadOnlyRegion> sorted = new List <IReadOnlyRegion>(regions.Where(region => region.QueryCallback == null));

            if (sorted.Count == 0)
            {
                return(new FrugalList <ReadOnlySpan>());
            }
            else if (sorted.Count == 1)
            {
                return(new FrugalList <ReadOnlySpan>()
                {
                    new ReadOnlySpan(version, sorted[0])
                });
            }
            else
            {
                sorted.Sort((s1, s2) => s1.Span.GetSpan(version).Start.CompareTo(s2.Span.GetSpan(version).Start));

                List <ReadOnlySpan> normalized = new List <ReadOnlySpan>(sorted.Count);

                int oldStart = sorted[0].Span.GetSpan(version).Start;
                int oldEnd   = sorted[0].Span.GetSpan(version).End;
                EdgeInsertionMode oldStartEdgeInsertionMode = sorted[0].EdgeInsertionMode;
                EdgeInsertionMode oldEndEdgeInsertionMode   = sorted[0].EdgeInsertionMode;
                SpanTrackingMode  oldSpanTrackingMode       = sorted[0].Span.TrackingMode;
                for (int i = 1; (i < sorted.Count); ++i)
                {
                    int newStart = sorted[i].Span.GetSpan(version).Start;
                    int newEnd   = sorted[i].Span.GetSpan(version).End;

                    // Since the new span's start occurs after the old span's end, we can just add the old span directly.
                    if (oldEnd < newStart)
                    {
                        normalized.Add(new ReadOnlySpan(version, new Span(oldStart, oldEnd - oldStart), oldSpanTrackingMode, oldStartEdgeInsertionMode, oldEndEdgeInsertionMode));
                        oldStart = newStart;
                        oldEnd   = newEnd;
                        oldStartEdgeInsertionMode = sorted[i].EdgeInsertionMode;
                        oldEndEdgeInsertionMode   = sorted[i].EdgeInsertionMode;
                        oldSpanTrackingMode       = sorted[i].Span.TrackingMode;
                    }
                    else
                    {
                        // The two read only regions start at the same position
                        if (newStart == oldStart)
                        {
                            // If one read only region denies edge insertions, combined they do as well
                            if (sorted[i].EdgeInsertionMode == EdgeInsertionMode.Deny)
                            {
                                oldStartEdgeInsertionMode = EdgeInsertionMode.Deny;
                            }

                            // This is tricky. We want one span that will be inclusive tracking, and one that won't.
                            if (oldSpanTrackingMode != sorted[i].Span.TrackingMode)
                            {
                                // Since the read only regions cover the same exact span, the combined one will be edge inclusive tracking
                                if (oldEnd == newEnd)
                                {
                                    oldSpanTrackingMode = SpanTrackingMode.EdgeInclusive;
                                }
                                else if (oldEnd < newEnd)
                                {
                                    // Since the old span and new span don't have the same span tracking mode and don't end in the same position, we need to create a new span that is edge inclusive
                                    // and deny inserts between it and the next span.
                                    normalized.Add(new ReadOnlySpan(version, new Span(oldStart, oldEnd - oldStart), SpanTrackingMode.EdgeInclusive, oldStartEdgeInsertionMode, EdgeInsertionMode.Deny));
                                    oldStart = oldEnd; // Explicitly use the old end here since we want these spans to be adjacent
                                    oldEnd   = newEnd;
                                    oldStartEdgeInsertionMode = sorted[i].EdgeInsertionMode;
                                    oldEndEdgeInsertionMode   = sorted[i].EdgeInsertionMode;
                                    oldSpanTrackingMode       = sorted[i].Span.TrackingMode;
                                }
                                else
                                {
                                    // Since the new span ends first, create a span that is edge inclusive tracking that ends at the the new span's end.
                                    normalized.Add(new ReadOnlySpan(version, new Span(newStart, newEnd - newStart), SpanTrackingMode.EdgeInclusive, oldStartEdgeInsertionMode, EdgeInsertionMode.Deny));
                                    oldStart = newEnd; // Explicitly use the new end here since we want these spans to be adjacent
                                }
                            }
                        }

                        if (oldEnd < newEnd)
                        {
                            // If the tracking modes are different then we need to create a new span
                            // with the old tracking mode, and start a new span with the new span tracking mode.
                            // Also, if the old end and the new start are identical and both edge insertion mode's
                            // are allow, then we need to create a new span.
                            if (((oldEnd == newStart)
                                 &&
                                 ((oldEndEdgeInsertionMode == EdgeInsertionMode.Allow) && (sorted[i].EdgeInsertionMode == EdgeInsertionMode.Allow)))
                                ||
                                (oldSpanTrackingMode != sorted[i].Span.TrackingMode))
                            {
                                normalized.Add(new ReadOnlySpan(version, new Span(oldStart, oldEnd - oldStart), oldSpanTrackingMode, oldStartEdgeInsertionMode, oldEndEdgeInsertionMode));
                                oldStart = oldEnd; // Explicitly use the old end here since we want these spans to be adjacent.
                                oldEnd   = newEnd;

                                // If we are splitting up the spans because of a change in tracking mode, then explicitly deny inserting between them
                                if (oldSpanTrackingMode != sorted[i].Span.TrackingMode)
                                {
                                    oldStartEdgeInsertionMode = EdgeInsertionMode.Deny; // Explicitly use deny here since we don't want to allow insertions between these spans
                                }
                                else
                                {
                                    oldStartEdgeInsertionMode = EdgeInsertionMode.Allow;
                                }
                                oldEndEdgeInsertionMode = sorted[i].EdgeInsertionMode;
                                oldSpanTrackingMode     = sorted[i].Span.TrackingMode;
                            }
                            else
                            {
                                oldEnd = newEnd;
                                oldEndEdgeInsertionMode = sorted[i].EdgeInsertionMode;
                            }
                        }
                        else if (oldEnd == newEnd)
                        {
                            if (sorted[i].EdgeInsertionMode == EdgeInsertionMode.Deny)
                            {
                                oldEndEdgeInsertionMode = EdgeInsertionMode.Deny;
                            }
                            if (oldSpanTrackingMode != sorted[i].Span.TrackingMode)
                            {
                                normalized.Add(new ReadOnlySpan(version, new Span(oldStart, oldEnd - oldStart), oldSpanTrackingMode, oldStartEdgeInsertionMode, oldEndEdgeInsertionMode));
                                oldStart = newEnd;
                                oldEnd   = newEnd;
                                oldStartEdgeInsertionMode = sorted[i].EdgeInsertionMode;
                                oldEndEdgeInsertionMode   = sorted[i].EdgeInsertionMode;
                                oldSpanTrackingMode       = sorted[i].Span.TrackingMode;
                            }
                        }
                    }
                }
                normalized.Add(new ReadOnlySpan(version, new Span(oldStart, oldEnd - oldStart), oldSpanTrackingMode, oldStartEdgeInsertionMode, oldEndEdgeInsertionMode));

                return(normalized);
            }
        }