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))); }
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>()); } }