Esempio n. 1
0
 protected void RefreshAllTags(ITextSnapshot snapshot)
 {
     Debug.Assert(!(snapshot is null));
     if (snapshot is null)
     {
         return;
     }
     lock (lockObj) {
         lastSnapshotState?.Cancel();
         lastSnapshotState?.FreeRef();
         lastSnapshotState = null;
         cachedTags.Clear();
     }
     TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length)));
 }
Esempio n. 2
0
        public IEnumerable <ITagSpan <TTagType> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {
                return(Enumerable.Empty <ITagSpan <TTagType> >());
            }

            var snapshot = spans[0].Snapshot;

            // The common case is spans.Count == 1, so try to prevent extra allocations
            IEnumerable <ITagSpan <TTagType> > singleResult    = null;
            List <ITagSpan <TTagType> >        multipleResults = null;
            SnapshotSpan?       singleMissingSpan    = null;
            List <SnapshotSpan> multipleMissingSpans = null;

            lock (lockObj) {
                if (lastSnapshotState?.Snapshot != snapshot)
                {
                    lastSnapshotState?.Cancel();
                    lastSnapshotState?.FreeRef();
                    cachedTags.Clear();

                    lastSnapshotState = new SnapshotState(snapshot);
                    lastSnapshotState.AddRef();
                }

                foreach (var span in spans)
                {
                    IEnumerable <ITagSpan <TTagType> > tags;
                    if (cachedTags.TryGetValue(span.Start.Position, out tags))
                    {
                        if (singleResult == null)
                        {
                            singleResult = tags;
                        }
                        else
                        {
                            if (multipleResults == null)
                            {
                                multipleResults = new List <ITagSpan <TTagType> >(singleResult);
                            }
                            multipleResults.AddRange(tags);
                        }
                    }
                    else
                    {
                        if (singleMissingSpan == null)
                        {
                            singleMissingSpan = span;
                        }
                        else
                        {
                            if (multipleMissingSpans == null)
                            {
                                multipleMissingSpans = new List <SnapshotSpan>()
                                {
                                    singleMissingSpan.Value
                                }
                            }
                            ;
                            multipleMissingSpans.Add(span);
                        }
                    }
                }
            }
            Debug.Assert(multipleResults == null || multipleResults.Count >= 2);
            Debug.Assert(multipleMissingSpans == null || multipleMissingSpans.Count >= 2);

            if (singleMissingSpan != null)
            {
                if (spans.Count != (multipleMissingSpans?.Count ?? 1))
                {
                    spans = multipleMissingSpans != null ?
                            new NormalizedSnapshotSpanCollection(multipleMissingSpans) :
                            new NormalizedSnapshotSpanCollection(singleMissingSpan.Value);
                }

                lock (lockObj) {
                    var lastSnapshotStateTmp = lastSnapshotState;
                    lastSnapshotStateTmp.GetTagsStateImpl.AddJob(spans);
                    if (!lastSnapshotStateTmp.TaskStarted)
                    {
                        lastSnapshotStateTmp.TaskStarted = true;
                        lastSnapshotStateTmp.AddRef();
                        GetTagsAsync(lastSnapshotStateTmp)
                        .ContinueWith(t => {
                            lastSnapshotStateTmp.FreeRef();
                            var ex = t.Exception;
                            if (t.IsCompleted && !t.IsCanceled && !t.IsFaulted)
                            {
                                SaveResult(t.Result);
                            }
                        });
                    }
                }
            }

            return(multipleResults ?? singleResult ?? Enumerable.Empty <ITagSpan <TTagType> >());
        }

        void SaveResult(TagsResult[] tagsResultList)
        {
            if (tagsResultList.Length == 0)
            {
                return;
            }

            bool sameSnapshot = tagsResultList[0].Span.Snapshot == lastSnapshotState.Snapshot;

            if (sameSnapshot)
            {
                lock (lockObj) {
                    foreach (var result in tagsResultList)
                    {
                        cachedTags[result.Span.Span.Start] = result.Tags;
                    }
                }

                foreach (var result in tagsResultList)
                {
                    TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(result.Span));
                }
            }
        }

        async Task <TagsResult[]> GetTagsAsync(SnapshotState snapshotState)
        {
            try {
                NormalizedSnapshotSpanCollection spans;
                for (;;)
                {
                    lock (lockObj) {
                        spans = snapshotState.GetTagsStateImpl.TryGetJob();
                        if (spans == null)
                        {
                            snapshotState.TaskStarted = false;
                            return(snapshotState.GetTagsStateImpl.GetResult());
                        }
                    }

                    snapshotState.GetTagsStateImpl.OnStartNewJob(spans);
                    await GetTagsAsync(snapshotState.GetTagsStateImpl, spans).ConfigureAwait(false);

                    snapshotState.GetTagsStateImpl.OnEndNewJob(spans);
                }
            }
            catch (OperationCanceledException) {
                throw;
            }
            catch {
                return(Array.Empty <TagsResult>());
            }
        }