Esempio n. 1
0
        public bool TryGetTextChanged(TextContentChangedEventArgs args, out string replacementText)
        {
            // make sure I am not called with my own changes
            Contract.ThrowIfTrue(this.MyOwnChanges(args));

            // initialize out parameter
            replacementText = null;

            var trackingSpansAfterEdit = GetActiveSpansForSnapshot(args.After).Select(ss => (Span)ss).ToList();
            var normalizedTrackingSpansAfterEdit = new NormalizedSpanCollection(trackingSpansAfterEdit);

            if (trackingSpansAfterEdit.Count != normalizedTrackingSpansAfterEdit.Count)
            {
                // Because of this edit, some spans merged together. We'll abort
                return false;
            }

            // We want to find the single tracking span that encompasses all the edits made.  If there 
            // is no such tracking span (or there are multiple), then we consider the change invalid
            // and we don't return any changed text.  If there is only one, then we find the text in
            // the new document.
            //
            // Note there may be multiple intersecting spans in the case where user typing causes 
            // multiple edits to happen.  For example, if the user has "Sub" and replaces it with "fu<tab>"
            // Then there will be multiple edits due to the text change and then the case correction.
            // However, both edits will be encompassed in one tracking span.
            var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));
            var intersection = NormalizedSpanCollection.Intersection(normalizedTrackingSpansAfterEdit, spansTouchedInEdit);

            var query = from trackingSpan in _trackingSpans
                        let mappedSpan = trackingSpan.GetSpan(args.After)
                        where intersection.All(intersectionSpan => mappedSpan.IntersectsWith(intersectionSpan))
                        select trackingSpan;

            var trackingSpansThatIntersect = query.ToList();
            if (trackingSpansThatIntersect.Count != 1)
            {
                return false;
            }

            var singleIntersectingTrackingSpan = trackingSpansThatIntersect.Single();
            replacementText = singleIntersectingTrackingSpan.GetText(args.After);
            return true;
        }
        /// <summary>
        /// Gets nested outlining regions for buffer
        /// </summary>
        protected void Outline()
        {
            ITextSnapshot  snapshot = Buffer.CurrentSnapshot;
            SnapshotParser parser   = GetSnapshotParser(snapshot);
            //parsing snapshot
            TextRegion regionTree = Outliner.ParseBuffer(parser);

            List <TextRegion> newRegions = GetRegionList(regionTree);

            List <Span> oldSpans = Regions.ConvertAll(r => r.AsSnapshotSpan().TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive).Span);
            List <Span> newSpans = newRegions.ConvertAll(r => r.AsSnapshotSpan().Span);

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.Snapshot = snapshot;
            this.Regions  = newRegions;

            if (changeStart <= changeEnd && this.TagsChanged != null)
            {
                this.TagsChanged(this, new SnapshotSpanEventArgs(
                                     new SnapshotSpan(this.Snapshot, Span.FromBounds(changeStart, changeEnd))));
            }
            FirstOutlining = false;
        }
        private void updateChangedSpans(ITextSnapshot newSnapshot, IList <Region> newRegions)
        {
            //determine the changed span, and send a changed event with the new spans
            IList <Span> oldSpans =
                new List <Span>(this._regions.Select(r => CodeFoldingTagger.AsSnapshotSpan(r, this._snapshot)
                                                     .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                     .Span));
            IList <Span> newSpans = new List <Span>(newRegions.Select(r => CodeFoldingTagger.AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }
            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this._snapshot = newSnapshot;
            this._regions  = newRegions;
            if (changeStart <= changeEnd)
            {
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(this._snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
                else
                {
                    AsmDudeToolsStatic.Output("reparse_Sync: TagsChanged is null");
                }
            }
        }
        private void CheckIfTagsChanged(SnapshotRegions oldSnapshotRegions, SnapshotRegions newSnapshotRegions)
        {
            ITextSnapshot          oldSnapshot = oldSnapshotRegions.Snapshot;
            IReadOnlyList <Region> oldRegions  = oldSnapshotRegions.Regions;
            ITextSnapshot          newSnapshot = newSnapshotRegions.Snapshot;
            IReadOnlyList <Region> newRegions  = newSnapshotRegions.Regions;

            // Determine the changed spans and send a changed event with the new spans.
            List <Span> oldSpans = new List <Span>(
                oldRegions.Select(r => AsSnapshotSpan(r, oldSnapshot).TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span));
            List <Span> newSpans = new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            // The changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            if (changeStart <= changeEnd)
            {
                var handler = this.TagsChanged;
                if (handler != null)
                {
                    var args = new SnapshotSpanEventArgs(new SnapshotSpan(newSnapshot, Span.FromBounds(changeStart, changeEnd)));
                    handler(this, args);
                }
            }
        }
Esempio n. 5
0
 public IProjectionSnapshot Apply(NormalizedSpanCollection spansToElide, NormalizedSpanCollection spansToExpand)
 {
     this.applied = true;
     try
     {
         if (spansToElide == null)
         {
             spansToElide = NormalizedSpanCollection.Empty;
         }
         if (spansToExpand == null)
         {
             spansToExpand = NormalizedSpanCollection.Empty;
         }
         if (spansToElide.Count > 0 || spansToExpand.Count > 0)
         {
             if ((spansToElide.Count > 0) && (spansToElide[spansToElide.Count - 1].End > this.elBuffer.sourceSnapshot.Length))
             {
                 throw new ArgumentOutOfRangeException(nameof(spansToElide));
             }
             if ((spansToExpand.Count > 0) && (spansToExpand[spansToExpand.Count - 1].End > this.elBuffer.sourceSnapshot.Length))
             {
                 throw new ArgumentOutOfRangeException(nameof(spansToExpand));
             }
             ElisionSourceSpansChangedEventArgs args = this.elBuffer.ApplySpanChanges(spansToElide, spansToExpand);
             if (args != null)
             {
                 ElisionSourceSpansChangedEventRaiser raiser = new ElisionSourceSpansChangedEventRaiser(args);
                 this.baseBuffer.group.EnqueueEvents(raiser, this.baseBuffer);
                 raiser.RaiseEvent(this.baseBuffer, true);
             }
             this.baseBuffer.editInProgress = false;
         }
         else
         {
             this.baseBuffer.editInProgress = false;
         }
     }
     finally
     {
         this.baseBuffer.group.FinishEdit();
     }
     return(this.elBuffer.currentElisionSnapshot);
 }
Esempio n. 6
0
        private ElisionSourceSpansChangedEventArgs ApplySpanChanges(NormalizedSpanCollection spansToElide, NormalizedSpanCollection spansToExpand)
        {
            ElisionSnapshot         beforeSnapshot = this.currentElisionSnapshot;
            FrugalList <TextChange> textChanges;
            ElisionMap newContent = this.content.EditSpans(this.sourceSnapshot, spansToElide, spansToExpand, out textChanges);

            if (newContent != this.content)
            {
                this.content = newContent;
                INormalizedTextChangeCollection normalizedChanges = NormalizedTextChangeCollection.Create(textChanges);
                SetCurrentVersionAndSnapshot(normalizedChanges);
                return(new ElisionSourceSpansChangedEventArgs(beforeSnapshot, this.currentElisionSnapshot,
                                                              spansToElide, spansToExpand, null));
            }
            else
            {
                return(null);
            }
        }
Esempio n. 7
0
        /// <summary>
        ///   Publishes the tag changes.
        /// </summary>
        /// <remarks>
        ///   Once the tags are parsed from the current document, they are passed into this method
        ///   in order to determine if anything has changed. Once the change detection is done,
        ///   it replaces <see cref = "Snapshot" /> for the tagger with the parameter passed in as
        ///   well as the <see cref = "Tags" />. If there were any changes, the <see cref = "E:TagsChanged" />
        ///   is raised with the combined snapshot of all changes made.
        /// </remarks>
        /// <param name = "newSnapshot">The new snapshot.</param>
        /// <param name = "newTags">The new tags.</param>
        protected virtual void PublishTagChanges(ITextSnapshot newSnapshot, List <TTokenTag> newTags)
        {
            ReadOnlyCollection <TTokenTag> currentTags = Tags;
            var oldSpans =
                new List <Span>(currentTags.Select(tag => tag.Span.TranslateTo(newSnapshot,
                                                                               SpanTrackingMode.EdgeExclusive)
                                                   .Span));
            var newSpans =
                new List <Span>(newTags.Select(tag => tag.Span.Span));

            var oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            var newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            Snapshot = newSnapshot;
            Tags     = newTags.AsReadOnly();

            if (changeStart <= changeEnd)
            {
                var snapshot = new SnapshotSpan(newSnapshot, Span.FromBounds(changeStart, changeEnd));
                OnTagsChanged(new SnapshotSpanEventArgs(snapshot));
            }
        }
Esempio n. 8
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = textBuffer.CurrentSnapshot;

            // Store off the current spans.
            var oldSpans = new List <Span>(this.RegionParser.CurlyBraceRegions.Select(r => AsSnapshotSpan(r, this.currentSnapshot)
                                                                                      .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span));

            this.RegionParser.Parse(newSnapshot);

            // Determine the changed span, and send a changed event with the new spans
            var newSpans = new List <Span>(this.RegionParser.CurlyBraceRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            // The changed regions are regions that appear in one set or the other, but not both.
            var oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            var newSpanCollection = new NormalizedSpanCollection(newSpans);
            var removed           = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.currentSnapshot = newSnapshot;

            if (changeStart <= changeEnd)
            {
                this.TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(this.currentSnapshot, Span.FromBounds(changeStart, changeEnd))));
            }
        }
        /// <summary>
        /// Search spans from [start ... spans.Count-1] for a span that contains point.
        /// If a span does contain point, return the index + 1
        /// If a span does not contain point, return the index of the first span that starts after point (or spans.Count if there are none).
        /// </summary>
        private static int IndexOfContainingSpan(NormalizedSpanCollection spans, int point, int start, bool isEndPoint)
        {
            int lo = start;
            int hi = spans.Count;

            while (lo < hi)
            {
                int  mid = (lo + hi) / 2;
                Span s   = spans[mid];

                if (s.End < point)
                {
                    lo = mid + 1;
                }
                else if (s.Start > point)
                {
                    hi = mid;
                }
                else
                {
                    //We know s.Start <= point <= s.End
                    //
                    //If point is an endPoint
                    //  we want to return mid + 1 if a span ending at point overlaps s (== point != s.Start). Otherwise return mid.
                    //
                    //If point is a startPoint
                    //  we want to return mid if a span starting at point overlaps s (== point == s.End). Otherwise return mid + 1.
                    if (isEndPoint)
                    {
                        return((point != s.Start) ? (mid + 1) : mid);
                    }
                    else
                    {
                        return((point == s.End) ? (mid + 1) : mid);
                    }
                }
            }

            return(lo);
        }
Esempio n. 10
0
        /// <summary>
        /// Kick off a background search if we don't have current results. Do nothing otherwise.
        /// </summary>
        /// <remarks>
        /// This method can be called from any thread (though it will generally only be called from the UI thread).
        /// </remarks>
        public void QueueSearch(NormalizedSnapshotSpanCollection requestedSnapshotSpans)
        {
            Debug.Assert(requestedSnapshotSpans.Count > 0);

            //Check to see if we have completely searched the current version of the text buffer
            //and quickly abort since there is no point in queuing up another search if we have.
            var results = _results;     //Snapshot results to avoid taking a lock.

            if (results.Snapshot == _buffer.CurrentSnapshot)
            {
                if ((results.SearchedSpans.Count == 1) && (results.SearchedSpans[0].Start == 0) && (results.SearchedSpans[0].Length == results.Snapshot.Length))
                {
                    //We've searched the entire snapshot.
                    return;
                }

                if (requestedSnapshotSpans[0].Snapshot == results.Snapshot)
                {
                    NormalizedSpanCollection unsearchedRequest = NormalizedSpanCollection.Difference(requestedSnapshotSpans, results.SearchedSpans);
                    if (unsearchedRequest.Count == 0)
                    {
                        return;
                    }
                }
            }

            lock (_requestQueue)
            {
                _requestQueue.Enqueue(requestedSnapshotSpans);
                if (_requestQueue.Count != 1)
                {
                    //Request has been queued & we already have an active thread processing requests.
                    return;
                }
            }

            Task.Factory.StartNew(this.ProcessQueue, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default);
        }
Esempio n. 11
0
        public bool TryGetTextChanged(TextContentChangedEventArgs args, out string replacementText)
        {
            // make sure I am not called with my own changes
            Contract.ThrowIfTrue(this.MyOwnChanges(args));

            // initialize out parameter
            replacementText = null;

            var trackingSpansAfterEdit           = GetActiveSpansForSnapshot(args.After).Select(ss => (Span)ss).ToList();
            var normalizedTrackingSpansAfterEdit = new NormalizedSpanCollection(trackingSpansAfterEdit);

            if (trackingSpansAfterEdit.Count != normalizedTrackingSpansAfterEdit.Count)
            {
                // Because of this edit, some spans merged together. We'll abort
                return(false);
            }

            var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));
            var intersection       = NormalizedSpanCollection.Intersection(normalizedTrackingSpansAfterEdit, spansTouchedInEdit);

            if (intersection.Count == 0)
            {
                // This edit didn't touch any spans, so ignore it
                return(false);
            }
            else if (intersection.Count > 1)
            {
                // TODO: figure out what the proper bail is in the new model
                return(false);
            }

            // Good, we touched just one, so let's propagate it
            var intersectionSpan          = intersection.Single();
            var singleTrackingSpanTouched = _trackingSpans.Single(ts => ts.GetSpan(args.After).IntersectsWith(intersectionSpan));

            replacementText = singleTrackingSpanTouched.GetText(args.After);
            return(true);
        }
Esempio n. 12
0
        public bool TryGetTextChanged(TextContentChangedEventArgs args, out string replacementText)
        {
            // make sure I am not called with my own changes
            Contract.ThrowIfTrue(this.MyOwnChanges(args));

            // initialize out parameter
            replacementText = null;

            var trackingSpansAfterEdit = GetActiveSpansForSnapshot(args.After).Select(ss => (Span)ss).ToList();
            var normalizedTrackingSpansAfterEdit = new NormalizedSpanCollection(trackingSpansAfterEdit);

            if (trackingSpansAfterEdit.Count != normalizedTrackingSpansAfterEdit.Count)
            {
                // Because of this edit, some spans merged together. We'll abort
                return false;
            }

            var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));
            var intersection = NormalizedSpanCollection.Intersection(normalizedTrackingSpansAfterEdit, spansTouchedInEdit);

            if (intersection.Count == 0)
            {
                // This edit didn't touch any spans, so ignore it
                return false;
            }
            else if (intersection.Count > 1)
            {
                // TODO: figure out what the proper bail is in the new model
                return false;
            }

            // Good, we touched just one, so let's propagate it
            var intersectionSpan = intersection.Single();
            var singleTrackingSpanTouched = _trackingSpans.Single(ts => ts.GetSpan(args.After).IntersectsWith(intersectionSpan));

            replacementText = singleTrackingSpanTouched.GetText(args.After);
            return true;
        }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit     = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersectionSpans = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);
                    if (intersectionSpans.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }

                    // Cases with invalid identifiers may cause there to be multiple intersection
                    // spans, but they should still all map to a single tracked rename span (e.g.
                    // renaming "two" to "one two three" may be interpreted as two distinct
                    // additions of "one" and "three").
                    var boundingIntersectionSpan = Span.FromBounds(intersectionSpans.First().Start, intersectionSpans.Last().End);
                    var trackingSpansTouched     = GetEditableSpansForSnapshot(args.After).Where(ss => ss.IntersectsWith(boundingIntersectionSpan));
                    Debug.Assert(trackingSpansTouched.Count() == 1);

                    var singleTrackingSpanTouched = trackingSpansTouched.Single();
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(boundingIntersectionSpan)).Single().Key;
                    _session.UndoManager.OnTextChanged(this.ActiveTextView.Selection, singleTrackingSpanTouched);
                }
            }
Esempio n. 14
0
        public ElisionBuffer(IProjectionEditResolver resolver,
                             IContentType contentType,
                             ITextBuffer sourceBuffer,
                             NormalizedSpanCollection exposedSpans,
                             ElisionBufferOptions options,
                             ITextDifferencingService textDifferencingService,
                             GuardedOperations guardedOperations)
            : base(resolver, contentType, textDifferencingService, guardedOperations)
        {
            Debug.Assert(sourceBuffer != null);
            this.sourceBuffer   = sourceBuffer;
            this.sourceSnapshot = sourceBuffer.CurrentSnapshot;

            Debug.Assert(sourceBuffer is BaseBuffer);
            BaseBuffer baseSourceBuffer = (BaseBuffer)sourceBuffer;

            this.eventHook = new WeakEventHook(this, baseSourceBuffer);

            this.group = baseSourceBuffer.group;
            this.group.AddMember(this);

            this.content = new ElisionMap(this.sourceSnapshot, exposedSpans);

            StringRebuilder newBuilder = StringRebuilder.Empty;

            for (int i = 0; (i < exposedSpans.Count); ++i)
            {
                newBuilder = newBuilder.Append(BufferFactoryService.StringRebuilderFromSnapshotAndSpan(this.sourceSnapshot, exposedSpans[i]));
            }
            this.builder = newBuilder;

            this.elisionOptions = options;
            this.currentVersion.SetLength(content.Length);
            this.currentElisionSnapshot = new ElisionSnapshot(this, this.sourceSnapshot, base.currentVersion, this.builder, this.content, (options & ElisionBufferOptions.FillInMappingMode) != 0);
            this.currentSnapshot        = this.currentElisionSnapshot;
        }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit     = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersection = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);

                    if (intersection.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }
                    else if (intersection.Count > 1)
                    {
                        Contract.Fail("we can't allow edits to touch multiple spans");
                    }

                    var intersectionSpan          = intersection.Single();
                    var singleTrackingSpanTouched = GetEditableSpansForSnapshot(args.After).Single(ss => ss.IntersectsWith(intersectionSpan));
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(intersectionSpan)).Single().Key;

                    _session.UndoManager.OnTextChanged(this.ActiveTextview.Selection, singleTrackingSpanTouched);
                }
            }
Esempio n. 16
0
        protected internal override NormalizedSpanCollection GetReadOnlyExtentsImplementation(Span span)
        {
            // TODO: make something other than dead slow

            FrugalList <Span> result = new FrugalList <Span>(base.GetReadOnlyExtentsImplementation(span));

            IList <SnapshotSpan> restrictionSpans = this.CurrentBaseSnapshot.MapToSourceSnapshotsForRead(span);

            foreach (SnapshotSpan restrictionSpan in restrictionSpans)
            {
                SnapshotSpan?overlapSpan = (restrictionSpan.Span == span) ? restrictionSpan : restrictionSpan.Overlap(span);
                if (overlapSpan.HasValue)
                {
                    BaseBuffer baseBuffer = (BaseBuffer)restrictionSpan.Snapshot.TextBuffer;
                    NormalizedSpanCollection sourceExtents = baseBuffer.GetReadOnlyExtents(overlapSpan.Value);
                    foreach (Span sourceExtent in sourceExtents)
                    {
                        result.AddRange(this.CurrentBaseSnapshot.MapFromSourceSnapshot(new SnapshotSpan(restrictionSpan.Snapshot, sourceExtent)));
                    }
                }
            }

            return(new NormalizedSpanCollection(result));
        }
Esempio n. 17
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            //keep the current (deepest) partial region, which will have
            // references to any parent partial regions.
            PartialRegion currentRegion = null;

            foreach (var line in newSnapshot.Lines)
            {
                int    regionStart = -1;
                string text        = line.GetText();

                //lines that contain a "[" denote the start of a new region.
                if ((regionStart = text.IndexOf(startHide, StringComparison.Ordinal)) != -1 || (regionStart = text.IndexOf(startHide.Replace(" ", string.Empty), StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int newLevel;
                    if (!TryGetLevel(text, regionStart, out newLevel))
                    {
                        newLevel = currentLevel + 1;
                    }

                    //levels are the same and we have an existing region;
                    //end the current region and start the next
                    if (currentLevel == newLevel && currentRegion != null)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentRegion.Level,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = line.LineNumber
                        });

                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion.PartialParent
                        };
                    }
                    //this is a new (sub)region
                    else
                    {
                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion
                        };
                    }
                }
                //lines that contain "]" denote the end of a region
                else if ((regionStart = text.IndexOf(endHide, StringComparison.Ordinal)) != -1 || (regionStart = text.IndexOf(endHide.Replace(" ", string.Empty), StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int closingLevel;
                    if (!TryGetLevel(text, regionStart, out closingLevel))
                    {
                        closingLevel = currentLevel;
                    }

                    //the regions match
                    if (currentRegion != null &&
                        currentLevel == closingLevel)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentLevel,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = line.LineNumber
                        });

                        currentRegion = currentRegion.PartialParent;
                    }
                }
            }

            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                    .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                    .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(
                                         new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }
Esempio n. 18
0
 public IProjectionSnapshot ModifySpans(NormalizedSpanCollection spansToElide, NormalizedSpanCollection spansToExpand)
 {
     using (SpanEdit spedit = new SpanEdit(this))
     {
         return(spedit.Apply(spansToElide, spansToExpand));
     }
 }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersectionSpans = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);
                    if (intersectionSpans.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }

                    // Cases with invalid identifiers may cause there to be multiple intersection
                    // spans, but they should still all map to a single tracked rename span (e.g.
                    // renaming "two" to "one two three" may be interpreted as two distinct
                    // additions of "one" and "three").
                    var boundingIntersectionSpan = Span.FromBounds(intersectionSpans.First().Start, intersectionSpans.Last().End);
                    var trackingSpansTouched = GetEditableSpansForSnapshot(args.After).Where(ss => ss.IntersectsWith(boundingIntersectionSpan));
                    Contract.Assert(trackingSpansTouched.Count() == 1);

                    var singleTrackingSpanTouched = trackingSpansTouched.Single();
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(boundingIntersectionSpan)).Single().Key;
                    _session.UndoManager.OnTextChanged(this.ActiveTextview.Selection, singleTrackingSpanTouched);
                }
            }
Esempio n. 20
0
        const int parse_fail    = -1; // a keyword hasn't been matched

        void ReParse()
        {
            m_regionStack.Clear();

            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            //var classifier = _classifierAggregator.GetClassifier(this.buffer);
            foreach (var line in newSnapshot.Lines)
            {
                /*if(classifier != null)
                 * {
                 *  var x = classifier.GetClassificationSpans(new SnapshotSpan(line.Start, line.Length));
                 *  x = x;
                 * }  */

                /*if(ReParse_Comment(line, newRegions) != parse_fail) continue;
                 * if(m_regionStack.Count > 0 && m_regionStack.Peek().Type == RegionType.RT_Comment)
                 * {
                 *  continue;
                 * }*/

                if (ReParse_Segment(line, newRegions) == parse_fail)
                {
                    if (ReParse_Procedure(line, newRegions) == parse_fail)
                    {
                        //ReParse_Condition(line, newRegions);
                    }
                }
            }

            newRegions = newRegions.Where(r => r.EndLine > -1).OrderBy(r => r.StartLine).ToList();
            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                    .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                    .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(
                                         new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }
Esempio n. 21
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            //keep the current (deepest) partial region, which will have
            // references to any parent partial regions.
            List <Region> parsedRegions     = new List <Region>();
            List <Region> parsedEndRegions  = new List <Region>();
            bool          undercommentscope = false;

            foreach (var line in newSnapshot.Lines)
            {
                int    currentpos   = 0;
                string text         = line.GetText();
                int    currentlevel = 0;
                int    regionstart  = 0;
                int    length       = text.Length;
                while (true)
                {
                    if (undercommentscope)
                    {
                        if ((regionstart = text.IndexOf(endComment, currentpos)) != -1)
                        {
                            Region region = parsedRegions.Last();
                            region.EndLine    = line.LineNumber;
                            region.EndLinePos = regionstart;
                            undercommentscope = false;
                            currentpos       += regionstart + endComment.Length;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        /*if((regionstart = text.IndexOf(cancelLine, currentpos)) != -1)
                         * {
                         *  break;
                         * }
                         * else*/if ((regionstart = text.IndexOf(startHide, currentpos)) != -1)
                        {
                            parsedRegions.Add(new Region()
                            {
                                StartLine = line.LineNumber, StartLinePos = regionstart, Level = currentlevel
                            });
                            currentlevel++;
                            currentpos += regionstart + startHide.Length;
                        }
                        else if ((regionstart = text.IndexOf(endHide, currentpos)) != -1)
                        {
                            currentlevel = Math.Max(currentlevel--, 0);
                            //parsedEndRegions.Add(new RegionEx() {EndLine = line.LineNumber, EndLinePos = regionstart, Level = currentlevel});
                            for (int i = parsedRegions.Count - 1; i >= 0; i--)
                            {
                                Region region = parsedRegions[i];
                                if (region.EndLinePos == -1)
                                {
                                    region.EndLine    = line.LineNumber;
                                    region.EndLinePos = regionstart;
                                    break;
                                }
                            }
                            currentpos += regionstart + endHide.Length;
                        }
                        else if ((regionstart = text.IndexOf(startComment, currentpos)) != -1)
                        {
                            parsedRegions.Add(new Region()
                            {
                                StartLine = line.LineNumber, StartLinePos = regionstart, Level = currentlevel, OutlineLength = startComment.Length
                            });
                            undercommentscope = true;
                            currentpos       += regionstart + startComment.Length;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (length <= currentpos)
                    {
                        break;
                    }
                }
            }

            List <Span> oldSpansEx = new List <Span>();

            foreach (Region r in this.regionsEX)
            {
                SnapshotSpan?span = AsSnapshotSpan(r, this.snapshot);
                if (span != null)
                {
                    oldSpansEx.Add(span.Value.TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span);
                }
            }
            List <Span> newSpansEx = new List <Span>();

            foreach (Region r in parsedRegions)
            {
                SnapshotSpan?span = AsSnapshotSpan(r, newSnapshot);
                if (span != null)
                {
                    oldSpansEx.Add(span.Value.Span);
                }
            }

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpansEx);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpansEx);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpansEx.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpansEx[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpansEx[newSpansEx.Count - 1].End);
            }

            this.snapshot  = newSnapshot;
            this.regionsEX = parsedRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(
                                         new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }
        private void ReParse()
        {
            ITextSnapshot newSnapshot = this.buffer.CurrentSnapshot;
            var           newRegions  = new List <SimpleRegion>();

            SimpleRegion currentRegion = null;

            foreach (var line in newSnapshot.Lines)
            {
                string text = line.GetText();

                var trimText = text.Trim();

                var isCommentOfInterest = false;

                if (trimText == "//" || trimText == "////" ||
                    trimText.StartsWith("// ") || trimText.StartsWith("////"))
                {
                    isCommentOfInterest = true;
                }

                if (isCommentOfInterest)
                {
                    if (currentRegion == null)
                    {
                        currentRegion = new SimpleRegion
                        {
                            StartLine   = line.LineNumber,
                            StartOffset = text.IndexOf("//"),
                        };
                    }
                }
                else
                {
                    if (currentRegion != null)
                    {
                        var endLineNumber = line.LineNumber - 1;

                        if (endLineNumber != currentRegion.StartLine)
                        {
                            currentRegion.EndLine = endLineNumber;
                            newRegions.Add(currentRegion);
                        }

                        currentRegion = null;
                    }
                }
            }

            if (currentRegion != null)
            {
                var endLineNumber = newSnapshot.Lines.Count() - 1;

                if (endLineNumber != currentRegion.StartLine)
                {
                    currentRegion.EndLine = endLineNumber;
                    newRegions.Add(currentRegion);
                }
            }

            // determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                    .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                    .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            // the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;

                this.TagsChanged?.Invoke(
                    this,
                    new SnapshotSpanEventArgs(
                        new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
            }
        }
Esempio n. 23
0
        public Task <object> CreateChangedDocumentPreviewViewAsync(Document oldDocument, Document newDocument, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Note: We don't use the original buffer that is associated with oldDocument
            // (and currently open in the editor) for oldBuffer below. This is because oldBuffer
            // will be used inside a projection buffer inside our inline diff preview below
            // and platform's implementation currently has a bug where projection buffers
            // are being leaked. This leak means that if we use the original buffer that is
            // currently visible in the editor here, the projection buffer span calculation
            // would be triggered every time user changes some code in this buffer (even though
            // the diff view would long have been dismissed by the time user edits the code)
            // resulting in crashes. Instead we create a new buffer from the same content.
            // TODO: We could use ITextBufferCloneService instead here to clone the original buffer.
            var oldBuffer = CreateNewBuffer(oldDocument, cancellationToken);
            var newBuffer = CreateNewBuffer(newDocument, cancellationToken);

            // Convert the diffs to be line based.
            // Compute the diffs between the old text and the new.
            var diffResult = ComputeEditDifferences(oldDocument, newDocument, cancellationToken);

            // Need to show the spans in the right that are different.
            // We also need to show the spans that are in conflict.
            var originalSpans = GetOriginalSpans(diffResult, cancellationToken);
            var changedSpans  = GetChangedSpans(diffResult, cancellationToken);

            var newRoot              = newDocument.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var conflictNodes        = newRoot.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);
            var conflictSpans        = conflictNodes.Select(n => n.Span.ToSpan()).ToList();
            var conflictDescriptions = conflictNodes.SelectMany(n => n.GetAnnotations(ConflictAnnotation.Kind))
                                       .Select(a => ConflictAnnotation.GetDescription(a))
                                       .Distinct();

            var warningNodes        = newRoot.GetAnnotatedNodesAndTokens(WarningAnnotation.Kind);
            var warningSpans        = warningNodes.Select(n => n.Span.ToSpan()).ToList();
            var warningDescriptions = warningNodes.SelectMany(n => n.GetAnnotations(WarningAnnotation.Kind))
                                      .Select(a => WarningAnnotation.GetDescription(a))
                                      .Distinct();

            AttachConflictAndWarningAnnotationToBuffer(newBuffer, conflictSpans, warningSpans);

            var description = conflictSpans.Count == 0 && warningSpans.Count == 0
                ? null
                : string.Join(Environment.NewLine, conflictDescriptions.Concat(warningDescriptions));

            var allSpans = new NormalizedSpanCollection(conflictSpans.Concat(warningSpans).Concat(changedSpans));

            var originalLineSpans = CreateLineSpans(oldBuffer.CurrentSnapshot, originalSpans, cancellationToken);
            var changedLineSpans  = CreateLineSpans(newBuffer.CurrentSnapshot, allSpans, cancellationToken);

            if (!originalLineSpans.Any())
            {
                // This means that we have no differences (likely because of conflicts).
                // In such cases, use the same spans for the left (old) buffer as the right (new) buffer.
                originalLineSpans = changedLineSpans;
            }

            // Create PreviewWorkspaces around the buffers to be displayed on the left and right
            // so that all IDE services (colorizer, squiggles etc.) light up in these buffers.
            var leftDocument = oldDocument.Project
                               .RemoveDocument(oldDocument.Id)
                               .AddDocument(oldDocument.Name, oldBuffer.AsTextContainer().CurrentText);
            var leftWorkspace = new PreviewWorkspace(leftDocument.Project.Solution);

            leftWorkspace.OpenDocument(leftDocument.Id);

            var rightWorkspace = new PreviewWorkspace(
                oldDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);

            rightWorkspace.OpenDocument(newDocument.Id);

            return(CreateChangedDocumentViewAsync(
                       oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                       leftWorkspace, rightWorkspace, zoomLevel, cancellationToken));
        }
Esempio n. 24
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = _buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            //keep the current (deepest) partial region, which will have
            // references to any parent partial _regions.
            PartialRegion currentRegion   = null;
            bool          comment_started = false;

            foreach (var line in newSnapshot.Lines)
            {
                int    regionStart = -1;
                string linetext    = line.GetText();

                string ellipsis_  = "";
                string end_text_  = "";
                string LabelName_ = "";
                bool   collapsed_ = false;


                string current_line = linetext.Replace('\t', ' ');
                current_line = current_line.TrimStart();

                bool regionFinished_comment = false;

                #region comment section
                int comment_start = current_line.IndexOf("//", StringComparison.Ordinal);
                if (comment_start == 0 && !comment_started)
                {
                    regionStart     = comment_start;
                    ellipsis_       = linetext.Substring(comment_start + 2, linetext.Length - comment_start - 2).Trim();
                    comment_started = true;
                    if (ellipsis_ == "")
                    {
                        ellipsis_ = "...";
                    }
                }
                if (comment_start != 0 && comment_started)
                {
                    regionFinished_comment = true;
                }
                #endregion

                #region labels
                bool regionFinished_label = false;
                var  label_values         = current_line.Split(' ');
                if (label_values.Length >= 2)
                {
                    bool labelFound = Dictionary_asm.Labels.Contains(label_values[0]);
                    if (labelFound && label_values[0] != "global" && label_values[0] != "local")
                    {
                        if (label_values[0] != "end")
                        {
                            regionStart = current_line.IndexOf(label_values[0], StringComparison.Ordinal);
                            ellipsis_   = label_values[1].Replace('\"', ' ').Trim();
                            LabelName_  = ellipsis_;
                        }
                        else
                        {
                            regionFinished_label = true;
                            LabelName_           = label_values[1].Replace('\"', ' ').Trim();
                        }
                    }
                }
                #endregion

                #region closing the region
                if (regionFinished_comment || regionFinished_label)
                {
                    CloseRegion(newRegions, ref currentRegion, ref comment_started, line, linetext, LabelName_, regionFinished_comment);
                    if (regionFinished_comment && regionFinished_label)
                    {
                        CloseRegion(newRegions, ref currentRegion, ref comment_started, line, linetext, LabelName_);
                    }
                }
                #endregion

                #region opening the new region
                if (regionStart > -1)
                {
                    currentRegion = OpenRegion(newRegions, currentRegion, line, regionStart, ellipsis_, end_text_, LabelName_, collapsed_);
                }
                #endregion
            }
            if (comment_started)
            {
                CloseRegion(newRegions, ref currentRegion, ref comment_started, newSnapshot.Lines.Last(), newSnapshot.Lines.Last().GetText(), null);
            }


            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(_regions.Select(r => AsSnapshotSpan(r, _snapshot)
                                                .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed _regions are _regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            _snapshot = newSnapshot;
            _regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                if (TagsChanged != null)
                {
                    TagsChanged(this, new SnapshotSpanEventArgs(
                                    new SnapshotSpan(_snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }
Esempio n. 25
0
        public Task<object> CreateChangedDocumentPreviewViewAsync(Document oldDocument, Document newDocument, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Note: We don't use the original buffer that is associated with oldDocument
            // (and currently open in the editor) for oldBuffer below. This is because oldBuffer
            // will be used inside a projection buffer inside our inline diff preview below
            // and platform's implementation currently has a bug where projection buffers
            // are being leaked. This leak means that if we use the original buffer that is
            // currently visible in the editor here, the projection buffer span calculation
            // would be triggered every time user changes some code in this buffer (even though
            // the diff view would long have been dismissed by the time user edits the code)
            // resulting in crashes. Instead we create a new buffer from the same content.
            // TODO: We could use ITextBufferCloneService instead here to clone the original buffer.
            var oldBuffer = CreateNewBuffer(oldDocument, cancellationToken);
            var newBuffer = CreateNewBuffer(newDocument, cancellationToken);

            // Convert the diffs to be line based.  
            // Compute the diffs between the old text and the new.
            var diffResult = ComputeEditDifferences(oldDocument, newDocument, cancellationToken);

            // Need to show the spans in the right that are different.
            // We also need to show the spans that are in conflict.
            var originalSpans = GetOriginalSpans(diffResult, cancellationToken);
            var changedSpans = GetChangedSpans(diffResult, cancellationToken);
            var description = default(string);
            var allSpans = default(NormalizedSpanCollection);

            if (newDocument.SupportsSyntaxTree)
            {
                var newRoot = newDocument.GetSyntaxRootSynchronously(cancellationToken);
                var conflictNodes = newRoot.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);
                var conflictSpans = conflictNodes.Select(n => n.Span.ToSpan()).ToList();
                var conflictDescriptions = conflictNodes.SelectMany(n => n.GetAnnotations(ConflictAnnotation.Kind))
                                                        .Select(a => ConflictAnnotation.GetDescription(a))
                                                        .Distinct();

                var warningNodes = newRoot.GetAnnotatedNodesAndTokens(WarningAnnotation.Kind);
                var warningSpans = warningNodes.Select(n => n.Span.ToSpan()).ToList();
                var warningDescriptions = warningNodes.SelectMany(n => n.GetAnnotations(WarningAnnotation.Kind))
                                                        .Select(a => WarningAnnotation.GetDescription(a))
                                                        .Distinct();

                var suppressDiagnosticsNodes = newRoot.GetAnnotatedNodesAndTokens(SuppressDiagnosticsAnnotation.Kind);
                var suppressDiagnosticsSpans = suppressDiagnosticsNodes.Select(n => n.Span.ToSpan()).ToList();
                AttachAnnotationsToBuffer(newBuffer, conflictSpans, warningSpans, suppressDiagnosticsSpans);

                description = conflictSpans.Count == 0 && warningSpans.Count == 0
                    ? null
                    : string.Join(Environment.NewLine, conflictDescriptions.Concat(warningDescriptions));
                allSpans = new NormalizedSpanCollection(conflictSpans.Concat(warningSpans).Concat(changedSpans));
            }
            else
            {
                allSpans = new NormalizedSpanCollection(changedSpans);
            }

            var originalLineSpans = CreateLineSpans(oldBuffer.CurrentSnapshot, originalSpans, cancellationToken);
            var changedLineSpans = CreateLineSpans(newBuffer.CurrentSnapshot, allSpans, cancellationToken);
            if (!originalLineSpans.Any())
            {
                // This means that we have no differences (likely because of conflicts).
                // In such cases, use the same spans for the left (old) buffer as the right (new) buffer.
                originalLineSpans = changedLineSpans;
            }

            // Create PreviewWorkspaces around the buffers to be displayed on the left and right
            // so that all IDE services (colorizer, squiggles etc.) light up in these buffers.
            var leftDocument = oldDocument.Project
                .RemoveDocument(oldDocument.Id)
                .AddDocument(oldDocument.Name, oldBuffer.AsTextContainer().CurrentText, oldDocument.Folders, oldDocument.FilePath);
            var leftWorkspace = new PreviewWorkspace(leftDocument.Project.Solution);
            leftWorkspace.OpenDocument(leftDocument.Id);

            var rightWorkspace = new PreviewWorkspace(
                newDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);
            rightWorkspace.OpenDocument(newDocument.Id);

            return CreateChangedDocumentViewAsync(
                oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                leftWorkspace, rightWorkspace, zoomLevel, cancellationToken);
        }
Esempio n. 26
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            PartialRegion currentRegion = null;

            foreach (var line in newSnapshot.Lines)
            {
                int    regionStart = -1;
                string text        = line.GetText();

                if ((regionStart = text.IndexOf(Constants.BlockStartHide, StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;

                    if (!TryGetLevel(text, regionStart, out int newLevel))
                    {
                        newLevel = currentLevel + 1;
                    }

                    if (currentLevel == newLevel && currentRegion != null)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentRegion.Level,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = line.LineNumber
                        });

                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion.PartialParent
                        };
                    }
                    else
                    {
                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion
                        };
                    }
                }
                else if ((regionStart = text.IndexOf(Constants.BlockEndHide, StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;

                    if (!TryGetLevel(text, regionStart, out int closingLevel))
                    {
                        closingLevel = currentLevel;
                    }

                    if (currentRegion != null &&
                        currentLevel == closingLevel)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentLevel,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = line.LineNumber
                        });

                        currentRegion = currentRegion.PartialParent;
                    }
                }
            }

            List <Span> oldSpans =
                new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                    .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                    .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;

                this.TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
            }
        }
        internal void DecomposeSpans()
        {
            // Prepare spans for diffing. The basic idea is this: suppose we have input spans from some source snapshot as follows:
            //
            // deleted:  0..10
            // inserted: 0..3 7..10
            //
            // We would like to raise a text change event that indicates that the text from 3..7 was deleted, rather than
            // an event indicating that all the text from 0..10 was deleted and replaced. We could simply compute a string
            // difference of the before & after text, but there might be a lot of text (so that would be expensive), and we
            // also don't want to suppress eventing when identical text comes from different source buffers (which might have
            // different content types). So, this routine converts the input spans into a form suitable for diffing:
            //
            // deleted: 0..3 3..7 7..10
            // inserted 0..3 7..10
            //
            // then we compute the differences of the spans qua spans, which in this case will indicate that the span named "3..7"
            // was deleted, and that's what we use to generate text change events.

            // what to substitute for input spans during diffing
            this.deletedSurrogates  = new List <SnapshotSpan> [this.inputDeletedSnapSpans.Count];
            this.insertedSurrogates = new List <SnapshotSpan> [this.inputInsertedSnapSpans.Count];

            // collect spans by text buffer

            Dictionary <ITextSnapshot, List <Thing> > buffer2DeletedThings = new Dictionary <ITextSnapshot, List <Thing> >();

            for (int ds = 0; ds < this.inputDeletedSnapSpans.Count; ++ds)
            {
                SnapshotSpan ss = this.inputDeletedSnapSpans[ds];
                List <Thing> things;
                if (!buffer2DeletedThings.TryGetValue(ss.Snapshot, out things))
                {
                    things = new List <Thing>();
                    buffer2DeletedThings.Add(ss.Snapshot, things);
                }
                things.Add(new Thing(ss.Span, ds));

                // unrelated
                deletedSurrogates[ds] = new List <SnapshotSpan>();
            }

            Dictionary <ITextSnapshot, List <Thing> > buffer2InsertedThings = new Dictionary <ITextSnapshot, List <Thing> >();

            for (int ns = 0; ns < this.inputInsertedSnapSpans.Count; ++ns)
            {
                SnapshotSpan ss = this.inputInsertedSnapSpans[ns];
                List <Thing> things;
                if (!buffer2InsertedThings.TryGetValue(ss.Snapshot, out things))
                {
                    things = new List <Thing>();
                    buffer2InsertedThings.Add(ss.Snapshot, things);
                }
                things.Add(new Thing(ss.Span, ns));

                // unrelated
                insertedSurrogates[ns] = new List <SnapshotSpan>();
            }

            foreach (KeyValuePair <ITextSnapshot, List <Thing> > pair in buffer2DeletedThings)
            {
                List <Thing>  insertedThings;
                ITextSnapshot snapshot = pair.Key;
                if (buffer2InsertedThings.TryGetValue(snapshot, out insertedThings))
                {
                    List <Thing> deletedThings = pair.Value;
                    insertedThings.Sort(Comparison);
                    deletedThings.Sort(Comparison);

                    int i = 0;
                    int d = 0;
                    do
                    {
                        Span inserted = insertedThings[i].span;
                        Span deleted  = deletedThings[d].span;
                        Span?overlap  = inserted.Overlap(deleted);

                        if (overlap == null)
                        {
                            if (inserted.Start < deleted.Start)
                            {
                                i++;
                            }
                            else
                            {
                                d++;
                            }
                        }
                        else
                        {
                            NormalizedSpanCollection insertedResidue = NormalizedSpanCollection.Difference(new NormalizedSpanCollection(inserted),
                                                                                                           new NormalizedSpanCollection(overlap.Value));  // todo add overload to normalizedspancollection
                            if (insertedResidue.Count > 0)
                            {
                                int pos = insertedThings[i].position;
                                insertedThings.RemoveAt(i);
                                bool didOverlap = false;
                                int  ir         = 0;
                                while (ir < insertedResidue.Count)
                                {
                                    Span r = insertedResidue[ir];
                                    if (didOverlap || r.Start < overlap.Value.Start)
                                    {
                                        insertedThings.Insert(i++, new Thing(r, pos));
                                        ir++;
                                    }
                                    else
                                    {
                                        insertedThings.Insert(i++, new Thing(overlap.Value, pos));
                                        didOverlap = true;
                                    }
                                }
                                if (!didOverlap)
                                {
                                    insertedThings.Insert(i++, new Thing(overlap.Value, pos));
                                }
                                i--;
                            }

                            NormalizedSpanCollection deletedResidue = NormalizedSpanCollection.Difference(new NormalizedSpanCollection(deleted),
                                                                                                          new NormalizedSpanCollection(overlap.Value));
                            if (deletedResidue.Count > 0)
                            {
                                int pos = deletedThings[d].position;
                                deletedThings.RemoveAt(d);
                                bool didOverlap = false;
                                int  dr         = 0;
                                while (dr < deletedResidue.Count)
                                {
                                    Span r = deletedResidue[dr];
                                    if (didOverlap || r.Start < overlap.Value.Start)
                                    {
                                        deletedThings.Insert(d++, new Thing(r, pos));
                                        dr++;
                                    }
                                    else
                                    {
                                        deletedThings.Insert(d++, new Thing(overlap.Value, pos));
                                        didOverlap = true;
                                    }
                                }
                                if (!didOverlap)
                                {
                                    deletedThings.Insert(d++, new Thing(overlap.Value, pos));
                                }
                                d--;
                            }
                        }
                        if (inserted.End <= deleted.End)
                        {
                            i++;
                        }
                        if (deleted.End <= inserted.End)
                        {
                            d++;
                        }
                    } while (i < insertedThings.Count && d < deletedThings.Count);
                }
            }

            foreach (KeyValuePair <ITextSnapshot, List <Thing> > pair in buffer2DeletedThings)
            {
                foreach (Thing t in pair.Value)
                {
                    deletedSurrogates[t.position].Add(new SnapshotSpan(pair.Key, t.span));
                }
            }

            foreach (KeyValuePair <ITextSnapshot, List <Thing> > pair in buffer2InsertedThings)
            {
                foreach (Thing t in pair.Value)
                {
                    insertedSurrogates[t.position].Add(new SnapshotSpan(pair.Key, t.span));
                }
            }
        }
Esempio n. 28
0
        /// <summary>
        /// Recursively build span tree.
        /// </summary>
        /// <param name="sourceSpan">SnapshotSpan over the source segment covered by this subtree, including both exposed and hidden text.</param>
        /// <param name="exposedSpans">Set of exposed spans for the entire buffer.</param>
        /// <param name="lineNumbers">Precomputed line numbers at all seams.</param>
        /// <param name="slice">The slice of exposed spans in this subtree.</param>
        /// <returns></returns>
        private ElisionMapNode Build(SnapshotSpan sourceSpan, NormalizedSpanCollection exposedSpans, int[] lineNumbers, Span slice)
        {
            int  mid            = slice.Start + (slice.Length / 2);
            Span midExposedSpan = exposedSpans[mid];

            Span           leftSlice = Span.FromBounds(slice.Start, mid);
            ElisionMapNode left;
            Span           leftSpan;

            if (leftSlice.Length > 0)
            {
                leftSpan = Span.FromBounds(sourceSpan.Start, midExposedSpan.Start);
                left     = Build(new SnapshotSpan(sourceSpan.Snapshot, leftSpan), exposedSpans, lineNumbers, leftSlice);
                Debug.Assert(left.TotalSourceSize == leftSpan.Length);
            }
            else if (slice.Start == 0 && midExposedSpan.Start != 0)
            {
                Debug.Assert(sourceSpan.Start == 0);
                leftSpan = Span.FromBounds(0, midExposedSpan.Start);
                // the beginning of the buffer is elided. Do the special case of the first
                // node in the tree having an exposed size of zero.
                // TODO: figure this out in advance so we don't screw up the balance of the tree
                left = new ElisionMapNode(0, leftSpan.Length, 0,
                                          TextUtilities.ScanForLineCount(sourceSpan.Snapshot.GetText(leftSpan)),
                                          true);
            }
            else
            {
                leftSpan = new Span(midExposedSpan.Start, 0);
                left     = null;
            }

            Span           rightSlice = Span.FromBounds(mid + 1, slice.End);
            ElisionMapNode right;
            Span           rightSpan;

            if (rightSlice.Length > 0)
            {
                rightSpan = Span.FromBounds(exposedSpans[mid + 1].Start, sourceSpan.End);
                right     = Build(new SnapshotSpan(sourceSpan.Snapshot, rightSpan), exposedSpans, lineNumbers, rightSlice);
                Debug.Assert(right.TotalSourceSize == rightSpan.Length);
            }
            else
            {
                rightSpan = new Span(sourceSpan.End, 0);
                right     = null;
            }

            Span          midHiddenSpan  = Span.FromBounds(midExposedSpan.End, rightSpan.Start);
            ITextSnapshot sourceSnapshot = sourceSpan.Snapshot;

            int startLineNumber      = lineNumbers[2 * mid];
            int endExposedLineNumber = lineNumbers[2 * mid + 1];
            int endSourceLineNumber  = lineNumbers[2 * mid + 2];

            int exposedLineBreakCount = endExposedLineNumber - startLineNumber;
            int hiddenLineBreakCount  = endSourceLineNumber - endExposedLineNumber;

            return(new ElisionMapNode(midExposedSpan.Length,
                                      sourceSpan.Length - (leftSpan.Length + rightSpan.Length),
                                      exposedLineBreakCount,
                                      exposedLineBreakCount + hiddenLineBreakCount,
                                      left,
                                      right,
                                      false));
        }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersection = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);

                    if (intersection.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }
                    else if (intersection.Count > 1)
                    {
                        Contract.Fail("we can't allow edits to touch multiple spans");
                    }

                    var intersectionSpan = intersection.Single();
                    var singleTrackingSpanTouched = GetEditableSpansForSnapshot(args.After).Single(ss => ss.IntersectsWith(intersectionSpan));
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(intersectionSpan)).Single().Key;

                    _session.UndoManager.OnTextChanged(this.ActiveTextview.Selection, singleTrackingSpanTouched);
                }
            }
Esempio n. 30
0
        private void ReParse()
        {
            ParseTree.Builder.Node root        = ParseTree.Tree.Root();
            ITextSnapshot          newSnapshot = buffer.CurrentSnapshot;
            List <Region>          newRegions  = new List <Region>();
            Stack <char>           brackets    = new Stack <char>();
            Stack <int>            offsets     = new Stack <int>();
            int level = 0;

            //string text = newSnapshot.GetText();

            void Traverse(ParseTree.Builder.Node node)
            {
                if (node.name == "'['" || node.name == "'{'" || node.name == "'('")
                {
                    brackets.Push(node.name[1]);
                    offsets.Push(node.begin);
                    ++level;
                }

                if (brackets.Count != 0 && node.name[1] == bracePairs[brackets.Peek()])
                {
                    int beginLine = newSnapshot.GetLineFromPosition(offsets.Peek()).LineNumber;
                    int endLine   = newSnapshot.GetLineFromPosition(node.begin).LineNumber;
                    if (beginLine != endLine)
                    {
                        if (newRegions.Count != 0 && newRegions.Last().StartOffset == offsets.Peek() + 1 && newRegions.Last().EndOffset == node.begin - 1)
                        {
                            newRegions.Last().Level       = level;
                            newRegions.Last().StartLine   = beginLine;
                            newRegions.Last().EndLine     = endLine;
                            newRegions.Last().StartOffset = offsets.Peek();
                            newRegions.Last().EndOffset   = node.begin;
                            newRegions.Last().Type        = brackets.Peek();
                        }
                        else
                        {
                            newRegions.Add(new Region()
                            {
                                Level       = level,
                                StartLine   = beginLine,
                                EndLine     = endLine,
                                StartOffset = offsets.Peek(),
                                EndOffset   = node.begin,
                                Type        = brackets.Peek()
                            });
                        }
                    }

                    --level;
                    offsets.Pop();
                    brackets.Pop();
                }

                if (node.children == null)
                {
                    return;
                }

                foreach (var child in node.children)
                {
                    Traverse(child);
                }
            }

            Traverse(root);

            List <Span> oldSpans = new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, snapshot)
                                                                       .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span));
            List <Span> newSpans = new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            snapshot = newSnapshot;
            regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, Span.FromBounds(changeStart, changeEnd))));
            }
        }
Esempio n. 31
0
        private List<LineSpan> CreateLineSpans(ITextSnapshot textSnapshot, NormalizedSpanCollection allSpans, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var result = new List<LineSpan>();

            foreach (var span in allSpans)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var lineSpan = GetLineSpan(textSnapshot, span);
                MergeLineSpans(result, lineSpan);
            }

            return result;
        }
Esempio n. 32
0
        void ReParse()
        {
            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            // keep the current (deepest) partial region, which will have
            // references to any parent partial regions.
            PartialRegion currentRegion = null;

            foreach (var line in newSnapshot.Lines)
            {
                string text              = line.GetText();
                string type              = string.Empty;
                int    regionStart       = -1;
                int    currentTokenIndex = -1;

                // Support for multiple tokens
                if (this.GetTextTokenIndex(text, startTokens, out regionStart, out currentTokenIndex))
                {
                    type = "S"; // Start token
                }
                else if (this.GetTextTokenIndex(text, endTokens, out regionStart, out currentTokenIndex))
                {
                    type = "E"; // End token
                }
                //else
                //    continue;

                if (type == "S")
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int newLevel;
                    if (!TryGetLevel(text, regionStart, out newLevel))
                    {
                        newLevel = currentLevel + 1;
                    }

                    //levels are the same and we have an existing region;
                    //end the current region and start the next
                    if (currentLevel == newLevel && currentRegion != null)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentRegion.Level,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = line.LineNumber,
                            LineText    = currentRegion.LineText,
                            TokenIndex  = currentTokenIndex //currentRegion.TokenIndex
                        });

                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion.PartialParent,
                            LineText      = text,
                            TokenIndex    = currentTokenIndex
                        };
                    }
                    else //this is a new (sub)region
                    {
                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion,
                            LineText      = text,
                            TokenIndex    = currentTokenIndex
                        };
                    }
                }
                else if (type == "E")
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int closingLevel;
                    if (!TryGetLevel(text, regionStart, out closingLevel))
                    {
                        closingLevel = currentLevel;
                    }

                    //the regions match
                    if (currentRegion != null &&
                        currentLevel == closingLevel &&
                        currentTokenIndex == currentRegion.TokenIndex)
                    {
                        newRegions.Add(new Region()
                        {
                            Level       = currentLevel,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            LineText    = currentRegion.LineText,
                            TokenIndex  = currentRegion.TokenIndex,
                            EndLine     = line.LineNumber
                        });

                        currentRegion = currentRegion.PartialParent;
                    }
                }
            }

            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans = new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                                       .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                                       .Span));
            List <Span> newSpans = new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }
        public async Task <DifferenceViewerPreview?> CreateChangedDocumentPreviewViewAsync(Document oldDocument, Document newDocument, double zoomLevel, CancellationToken cancellationToken)
        {
            // CreateNewBufferAsync must be called from the main thread
            await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            // Note: We don't use the original buffer that is associated with oldDocument
            // (and currently open in the editor) for oldBuffer below. This is because oldBuffer
            // will be used inside a projection buffer inside our inline diff preview below
            // and platform's implementation currently has a bug where projection buffers
            // are being leaked. This leak means that if we use the original buffer that is
            // currently visible in the editor here, the projection buffer span calculation
            // would be triggered every time user changes some code in this buffer (even though
            // the diff view would long have been dismissed by the time user edits the code)
            // resulting in crashes. Instead we create a new buffer from the same content.
            // TODO: We could use ITextBufferCloneService instead here to clone the original buffer.
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            var oldBuffer = await CreateNewBufferAsync(oldDocument, cancellationToken);

            var newBuffer = await CreateNewBufferAsync(newDocument, cancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

            // Convert the diffs to be line based.
            // Compute the diffs between the old text and the new.
            var diffResult = ComputeEditDifferences(oldDocument, newDocument, cancellationToken);

            // Need to show the spans in the right that are different.
            // We also need to show the spans that are in conflict.
            var    originalSpans = GetOriginalSpans(diffResult, cancellationToken);
            var    changedSpans  = GetChangedSpans(diffResult, cancellationToken);
            string?description   = null;
            NormalizedSpanCollection allSpans;

            if (newDocument.SupportsSyntaxTree)
            {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
                var newRoot = await newDocument.GetRequiredSyntaxRootAsync(cancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                var conflictNodes        = newRoot.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);
                var conflictSpans        = conflictNodes.Select(n => n.Span.ToSpan()).ToList();
                var conflictDescriptions = conflictNodes.SelectMany(n => n.GetAnnotations(ConflictAnnotation.Kind))
                                           .Select(a => $"❌ {ConflictAnnotation.GetDescription(a)}")
                                           .Distinct();

                var warningNodes        = newRoot.GetAnnotatedNodesAndTokens(WarningAnnotation.Kind);
                var warningSpans        = warningNodes.Select(n => n.Span.ToSpan()).ToList();
                var warningDescriptions = warningNodes.SelectMany(n => n.GetAnnotations(WarningAnnotation.Kind))
                                          .Select(a => $"⚠ {WarningAnnotation.GetDescription(a)}")
                                          .Distinct();

                var suppressDiagnosticsNodes = newRoot.GetAnnotatedNodesAndTokens(SuppressDiagnosticsAnnotation.Kind);
                var suppressDiagnosticsSpans = suppressDiagnosticsNodes.Select(n => n.Span.ToSpan()).ToList();
                AttachAnnotationsToBuffer(newBuffer, conflictSpans, warningSpans, suppressDiagnosticsSpans);

                description = conflictSpans.Count == 0 && warningSpans.Count == 0
                    ? null
                    : string.Join(Environment.NewLine, conflictDescriptions.Concat(warningDescriptions));
                allSpans = new NormalizedSpanCollection(conflictSpans.Concat(warningSpans).Concat(changedSpans));
            }
            else
            {
                allSpans = new NormalizedSpanCollection(changedSpans);
            }

            var originalLineSpans = CreateLineSpans(oldBuffer.CurrentSnapshot, originalSpans, cancellationToken);
            var changedLineSpans  = CreateLineSpans(newBuffer.CurrentSnapshot, allSpans, cancellationToken);
            if (!originalLineSpans.Any())
            {
                // This means that we have no differences (likely because of conflicts).
                // In such cases, use the same spans for the left (old) buffer as the right (new) buffer.
                originalLineSpans = changedLineSpans;
            }

            // Create PreviewWorkspaces around the buffers to be displayed on the left and right
            // so that all IDE services (colorizer, squiggles etc.) light up in these buffers.
            var leftWorkspace = new PreviewWorkspace(oldDocument.Project.Solution);
            leftWorkspace.OpenDocument(oldDocument.Id, oldBuffer.AsTextContainer());

            var rightWorkspace = new PreviewWorkspace(newDocument.Project.Solution);
            rightWorkspace.OpenDocument(newDocument.Id, newBuffer.AsTextContainer());

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            return(await CreateChangedDocumentViewAsync(
                       oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                       leftWorkspace, rightWorkspace, zoomLevel, cancellationToken));

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
        }
Esempio n. 34
0
 public SearchResults(ITextSnapshot snapshot, NormalizedSpanCollection matches, NormalizedSpanCollection searchedSpans)
 {
     this.Snapshot      = snapshot;
     this.Matches       = matches;
     this.SearchedSpans = searchedSpans;
 }
        private void ParseAndCache()
        {
            if (!Invalidated)
            {
                lock (Timer)
                    Timer.Change(-1, -1);
                return;
            }
            try
            {
                Invalidated = false;
                var newSnapshot = Buffer.CurrentSnapshot;
                var newRegions  = new List <Region>();

                PartialRegion currentRegion = null;
                bool          validDsl;
                var           tokens = SyntaxParser.GetExtensions(newSnapshot, out validDsl);
                if (Invalidated)
                {
                    return;
                }
                int       currentLevel = 0;
                var       levelInfo    = new List <LevelInfo>(tokens.Length / 16 + 2);
                LevelInfo lastInfo     = null;
                for (int i = 0; i < tokens.Length; i++)
                {
                    var t = tokens[i];
                    if (t.Type == SyntaxType.RuleExtension)
                    {
                        lastInfo = new LevelInfo();
                        if (currentLevel < levelInfo.Count)
                        {
                            levelInfo[currentLevel] = lastInfo;
                        }
                        else
                        {
                            levelInfo.Add(lastInfo);
                        }
                        currentLevel++;
                        currentRegion = new PartialRegion
                        {
                            Rule          = t.Value,
                            Level         = currentLevel,
                            StartLine     = t.Line - 1,
                            StartOffset   = t.Column,
                            PartialParent = currentRegion
                        };
                    }
                    else if (t.Type == SyntaxType.RuleEnd)
                    {
                        if (currentRegion == null)
                        {
                            continue;
                        }
                        lastInfo.Level--;
                        if (lastInfo.Level >= 0)
                        {
                            continue;
                        }
                        currentLevel--;
                        newRegions.Add(new Region
                        {
                            Rule        = t.Value,
                            IsNested    = lastInfo.IsNested,
                            Level       = currentLevel,
                            StartLine   = currentRegion.StartLine,
                            StartOffset = currentRegion.StartOffset,
                            EndLine     = t.Line - 1,
                            EndOffset   = t.Column - 1
                        });
                        lastInfo = currentLevel > 0 ? levelInfo[currentLevel - 1] : null;
                        if (lastInfo != null)
                        {
                            lastInfo.Level--;
                        }
                        currentRegion = currentRegion.PartialParent;
                    }
                    else if (lastInfo != null)
                    {
                        lastInfo.Level++;
                        lastInfo.IsNested = true;
                    }
                }
                if (Invalidated)
                {
                    return;
                }

                int changeStart = 0;
                int changeEnd   = newSnapshot.Length;

                if (!validDsl)
                {
                    var oldSpans = new Span[Regions.Length];
                    for (int i = 0; i < Regions.Length; i++)
                    {
                        oldSpans[i] = AsSnapshotSpan(Regions[i], Snapshot).TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span;
                    }
                    var newSpans = new Span[newRegions.Count];
                    for (int i = 0; i < newRegions.Count; i++)
                    {
                        newSpans[i] = AsSnapshotSpan(newRegions[i], newSnapshot).Span;
                    }

                    var oldSpanCollection = new NormalizedSpanCollection(oldSpans);
                    var newSpanCollection = new NormalizedSpanCollection(newSpans);

                    //the changed regions are regions that appear in one set or the other, but not both.
                    var removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

                    if (removed.Count > 0)
                    {
                        changeStart = removed[0].Start;
                        changeEnd   = removed[removed.Count - 1].End;
                    }

                    if (newSpans.Length > 0)
                    {
                        changeStart = Math.Min(changeStart, newSpans[0].Start);
                        changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Length - 1].End);
                    }
                }
                if (Invalidated)
                {
                    return;
                }
                Snapshot = newSnapshot;
                Regions  = newRegions.ToArray();

                if (changeStart <= changeEnd)
                {
                    TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(newSnapshot, Span.FromBounds(changeStart, changeEnd))));
                }
                lock (Timer)
                    Timer.Change(1000, -1);
            }
            catch
            {
                lock (Timer)
                    Timer.Change(5000, -1);
            }
        }
Esempio n. 36
0
        void ReParse( )
        {
            m_regionStack.Clear();

            ITextSnapshot newSnapshot = buffer.CurrentSnapshot;
            List <Region> newRegions  = new List <Region>();

            //keep the current (deepest) partial region, which will have
            // references to any parent partial regions.
            PartialRegion currentRegion = null;

            foreach (var line in newSnapshot.Lines)
            {
                int    regionStart = -1;
                int    signStart   = -1;
                string text        = line.GetText();
                signStart = SimpleNasmLineParser.SkipSpace(text, 0);

                int    currentLevel = (currentRegion != null) ? currentRegion.Level : 0;
                Region rgn          = null;
                // %if, open a new region
                if ((regionStart = text.IndexOf(ConditionKeywords[0], StringComparison.InvariantCultureIgnoreCase)) != -1 &&
                    regionStart == signStart)
                {
                    m_regionStack.Push(new Region()
                    {
                        StartLine   = line.LineNumber,
                        StartOffset = line.Length
                    });
                }
                // %endif, close current region
                else if ((regionStart = text.IndexOf(ConditionKeywords[3], StringComparison.InvariantCultureIgnoreCase)) != -1 &&
                         regionStart == signStart)
                {
                    if (m_regionStack.Count == 0)
                    {
                        continue;
                    }

                    rgn         = m_regionStack.Pop();
                    rgn.EndLine = line.LineNumber;
                    newRegions.Add(rgn);
                }
                // %elif. %else, close current region and open a new region
                else if (((regionStart = text.IndexOf(ConditionKeywords[1], StringComparison.InvariantCultureIgnoreCase)) != -1 ||
                          (regionStart = text.IndexOf(ConditionKeywords[2], StringComparison.InvariantCultureIgnoreCase)) != -1) && regionStart == signStart)
                {
                    if (m_regionStack.Count == 0)
                    {
                        continue;
                    }

                    rgn         = m_regionStack.Pop();
                    rgn.EndLine = line.LineNumber - 1;
                    newRegions.Add(rgn);
                    m_regionStack.Push(new Region()
                    {
                        StartLine   = line.LineNumber,
                        StartOffset = line.Length
                    });
                }
            }

            newRegions = newRegions.Where(r => r.EndLine > -1).OrderBy(r => r.StartLine).ToList();
            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot)
                                                    .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive)
                                                    .Span));
            List <Span> newSpans =
                new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span));

            NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans);

            //the changed regions are regions that appear in one set or the other, but not both.
            NormalizedSpanCollection removed =
                NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            int changeStart = int.MaxValue;
            int changeEnd   = -1;

            if (removed.Count > 0)
            {
                changeStart = removed[0].Start;
                changeEnd   = removed[removed.Count - 1].End;
            }

            if (newSpans.Count > 0)
            {
                changeStart = Math.Min(changeStart, newSpans[0].Start);
                changeEnd   = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End);
            }

            this.snapshot = newSnapshot;
            this.regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this.snapshot;
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(
                                         new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
        }