示例#1
0
            public void FulfillOutstandingRequests()
            {
                Create("cat", "dog", "fish", "tree");
                _asyncTagger.ChunkCount = 1;
                _asyncTaggerSource.SetBackgroundFunc(
                    span =>
                {
                    var lineRange = SnapshotLineRange.CreateForSpan(span);
                    if (lineRange.LineRange.ContainsLineNumber(0))
                    {
                        return(span.Snapshot.GetLineFromLineNumber(0).Extent);
                    }

                    if (lineRange.LineRange.ContainsLineNumber(1))
                    {
                        return(span.Snapshot.GetLineFromLineNumber(1).Extent);
                    }

                    return(null);
                });

                for (int i = 0; i < _textBuffer.CurrentSnapshot.LineCount; i++)
                {
                    var span = _textBuffer.GetLineSpan(i, i);
                    var col  = new NormalizedSnapshotSpanCollection(span);
                    _asyncTagger.GetTags(col);
                }

                _asyncTaggerSource.Delay = null;
                WaitForBackgroundToComplete();

                var tags = _asyncTagger.GetTags(new NormalizedSnapshotSpanCollection(_textBuffer.GetExtent()));

                Assert.Equal(2, tags.Count());
            }
示例#2
0
        private IEnumerable <ITagSpan <TTag> > GetTags(SnapshotSpan span)
        {
            var lineRange = SnapshotLineRange.CreateForSpan(span);

            EditorUtilsTrace.TraceInfo("AsyncTagger::GetTags {0} - {1}", lineRange.StartLineNumber, lineRange.LastLineNumber);

            // First try and see if the tagger can provide prompt data.  We want to avoid
            // creating Task<T> instances if possible.
            IEnumerable <ITagSpan <TTag> > tagList = EmptyTagList;

            if (!TryGetTagsPrompt(span, out tagList) &&
                !TryGetTagsFromBackgroundDataCache(span, out tagList))
            {
                // The request couldn't be fully satisfied from the cache or prompt data so
                // we will request the data in the background thread
                GetTagsInBackground(span);

                // Since the request couldn't be fully fulfilled by the cache we augment the returned data
                // with our tracking data
                var trackingTagList = GetTagsFromTrackingDataCache(span.Snapshot);
                tagList = tagList == null
                    ? trackingTagList
                    : tagList.Concat(trackingTagList);
            }

            // Now filter the set of returned ITagSpan values to those which are part of the
            // requested NormalizedSnapshotSpanCollection.  The cache lookups don't dig down and
            // instead return all available tags.  We filter down the collection here to what's
            // necessary.
            return(tagList.Where(tagSpan => tagSpan.Span.IntersectsWith(span)));
        }
示例#3
0
        private void RaiseTagsChanged(SnapshotSpan span)
        {
            var lineRange = SnapshotLineRange.CreateForSpan(span);

            EditorUtilsTrace.TraceInfo("AsyncTagger::RaiseTagsChanged {0} - {1}", lineRange.StartLineNumber, lineRange.LastLineNumber);

            if (_tagsChanged != null)
            {
                _tagsChanged(this, new SnapshotSpanEventArgs(span));
            }
        }
示例#4
0
        internal AsyncTaggerType.AsyncBackgroundRequest CreateAsyncBackgroundRequest(
            SnapshotSpan span,
            CancellationTokenSource cancellationTokenSource,
            Task task = null)
        {
            var channel = new AsyncTagger <string, TextMarkerTag> .Channel();

            channel.WriteNormal(SnapshotLineRange.CreateForSpan(span));

            task = task ?? new Task(() => { });
            return(new AsyncTaggerType.AsyncBackgroundRequest(
                       span.Snapshot,
                       channel,
                       task,
                       cancellationTokenSource));
        }
            internal ReadOnlyCollection <ITagSpan <TextMarkerTag> > GetTags(SnapshotSpan span)
            {
                var lineRange = SnapshotLineRange.CreateForSpan(span);

                Debug.WriteLine("WordUnderCaret Version {0}, Lines {1} - {2}", span.Snapshot.Version.VersionNumber, lineRange.StartLineNumber, lineRange.LastLineNumber);

                var tags = new List <ITagSpan <TextMarkerTag> >();

                foreach (var snapshotLine in lineRange.Lines)
                {
                    AddWordsOnLine(tags, snapshotLine);
                    _cancellationToken.ThrowIfCancellationRequested();
                }

                return(tags.ToReadOnlyCollectionShallow());
            }
示例#6
0
        protected override ReadOnlyCollection <ITagSpan <TextMarkerTag> > GetTagsInBackground(string data, SnapshotSpan span, CancellationToken cancellationToken)
        {
            var lineRange = SnapshotLineRange.CreateForSpan(span);
            var list      = new List <ITagSpan <TextMarkerTag> >();

            foreach (var snapshotLine in lineRange.Lines)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var commentSpan = MatchLine(snapshotLine);
                if (commentSpan.HasValue)
                {
                    var tagSpan = new TagSpan <TextMarkerTag>(commentSpan.Value, s_tag);
                    list.Add(tagSpan);
                }
            }

            return(list.ToReadOnlyCollectionShallow());
        }
示例#7
0
            internal ReadOnlyCollection <ITagSpan <TextMarkerTag> > GetTags(SnapshotSpan span)
            {
                var tags      = new List <ITagSpan <TextMarkerTag> >();
                var lineRange = SnapshotLineRange.CreateForSpan(span);

                Debug.WriteLine("Cat Version {0}, Lines {1} - {2}", span.Snapshot.Version.VersionNumber, lineRange.StartLineNumber, lineRange.LastLineNumber);
                foreach (var snapshotLine in lineRange.Lines)
                {
                    AddWordsOnLine(tags, snapshotLine);
                    _cancellationToken.ThrowIfCancellationRequested();
                }

                // Cats need naps
                Debug.WriteLine("Cat Nap Time");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                Debug.WriteLine("Cat Wake Up");

                return(tags.ToReadOnlyCollectionShallow());
            }
示例#8
0
            /// <summary>
            /// Determine tag cache state we have for the given SnapshotSpan
            /// </summary>
            internal TagCacheState GetTagCacheState(SnapshotSpan span)
            {
                // If the requested span doesn't even intersect with the overarching SnapshotSpan
                // of the cached data in the background then a more exhaustive search isn't needed
                // at this time
                var cachedSpan = Span;

                if (!cachedSpan.IntersectsWith(span))
                {
                    return(TagCacheState.None);
                }

                var lineRange = SnapshotLineRange.CreateForSpan(span);
                var unvisited = VisitedCollection.GetUnvisited(lineRange.LineRange);

                return(unvisited.HasValue
                    ? TagCacheState.Partial
                    : TagCacheState.Complete);
            }
示例#9
0
 internal AsyncTaggerType.BackgroundCacheData CreateBackgroundCacheData(SnapshotSpan source, params SnapshotSpan[] tagSpans)
 {
     return(new AsyncTaggerType.BackgroundCacheData(
                SnapshotLineRange.CreateForSpan(source),
                tagSpans.Select(CreateTagSpan).ToReadOnlyCollection()));
 }
示例#10
0
 internal BackgroundCacheData <TextMarkerTag> CreateBackgroundCacheData(SnapshotSpan source, params SnapshotSpan[] tagSpans)
 {
     return(new BackgroundCacheData <TextMarkerTag>(
                SnapshotLineRange.CreateForSpan(source),
                tagSpans.Select(CreateTagSpan).ToReadOnlyCollection()));
 }
示例#11
0
        /// <summary>
        /// Get the tags for the specified SnapshotSpan in a background task.  If there are outstanding
        /// requests for SnapshotSpan values then this one will take priority over those
        /// </summary>
        private void GetTagsInBackground(SnapshotSpan span)
        {
            var synchronizationContext = SynchronizationContext.Current;

            if (null == synchronizationContext)
            {
                return;
            }

            // The background processing should now be focussed on the specified ITextSnapshot
            var snapshot = span.Snapshot;

            // In the majority case GetTags(NormalizedSnapshotCollection) drives this function and
            // AdjustToSnapshot is already called.  There are other code paths though within AsyncTagger
            // which call this method.  We need to guard against them here.
            AdjustToSnapshot(snapshot);

            // Our caching and partitioning of data is all done on a line range
            // basis.  Just expand the requested SnapshotSpan to the encompassing
            // SnaphotlineRange
            var lineRange = SnapshotLineRange.CreateForSpan(span);

            span = lineRange.ExtentIncludingLineBreak;

            // If we already have a background task running for this ITextSnapshot then just enqueue this
            // request onto that existing one.  By this point if the request exists it must be tuned to
            // this ITextSnapshot
            if (_asyncBackgroundRequest.HasValue)
            {
                var asyncBackgroundRequest = _asyncBackgroundRequest.Value;
                if (asyncBackgroundRequest.Snapshot == snapshot)
                {
                    Contract.Requires(asyncBackgroundRequest.Snapshot == snapshot);
                    EditorUtilsTrace.TraceInfo("AsyncTagger Background Existing {0} - {1}", lineRange.StartLineNumber, lineRange.LastLineNumber);
                    asyncBackgroundRequest.Channel.WriteNormal(lineRange);
                    return;
                }

                CancelAsyncBackgroundRequest();
            }

            Contract.Assert(!_asyncBackgroundRequest.HasValue);
            EditorUtilsTrace.TraceInfo("AsyncTagger Background New {0} - {1}", lineRange.StartLineNumber, lineRange.LastLineNumber);

            // Create the data which is needed by the background request
            var data = _asyncTaggerSource.GetDataForSnapshot(snapshot);
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken       = cancellationTokenSource.Token;
            var channel = new Channel();

            channel.WriteNormal(lineRange);

            // If there is an ITextView then make sure it is requested as well.  If the source provides an
            // ITextView then it is always prioritized on requests for a new snapshot
            if (_asyncTaggerSource.TextViewOptional != null)
            {
                var visibleLineRange = _asyncTaggerSource.TextViewOptional.GetVisibleSnapshotLineRange();
                if (visibleLineRange.HasValue)
                {
                    channel.WriteVisibleLines(visibleLineRange.Value);
                }
            }

            // The background thread needs to know the set of values we have already queried
            // for.  Send a copy since this data will be mutated from a background thread
            NormalizedLineRangeCollection localVisited;

            if (_tagCache.BackgroundCacheData.HasValue)
            {
                var backgroundCacheData = _tagCache.BackgroundCacheData.Value;
                Contract.Requires(backgroundCacheData.Snapshot == snapshot);
                localVisited = backgroundCacheData.VisitedCollection.Copy();
            }
            else
            {
                localVisited = new NormalizedLineRangeCollection();
            }

            // Function which finally gets the tags.  This is run on a background thread and can
            // throw as the implementor is encouraged to use CancellationToken::ThrowIfCancelled
            var    localAsyncTaggerSource = _asyncTaggerSource;
            var    localChunkCount        = _chunkCount;
            Action getTags = () => GetTagsInBackgroundCore(
                localAsyncTaggerSource,
                data,
                localChunkCount,
                channel,
                localVisited,
                cancellationToken,
                (completeReason) => synchronizationContext.Post(_ => OnGetTagsInBackgroundComplete(completeReason, channel, cancellationTokenSource), null),
                (processedLineRange, tagList) => synchronizationContext.Post(_ => OnGetTagsInBackgroundProgress(cancellationTokenSource, processedLineRange, tagList), null));

            // Create the Task which will handle the actual gathering of data.  If there is a delay
            // specified use it
            var    localDelay = _asyncTaggerSource.Delay;
            Action taskAction =
                () =>
            {
                if (localDelay.HasValue)
                {
                    Thread.Sleep(localDelay.Value);
                }

                getTags();
            };

            var task = new Task(taskAction, cancellationToken);

            _asyncBackgroundRequest = new AsyncBackgroundRequest(
                span.Snapshot,
                channel,
                task,
                cancellationTokenSource);

            task.Start();
        }