protected override async Task ProduceTagsAsync(TaggerContext <KeywordHighlightTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition)
        {
            var cancellationToken = context.CancellationToken;
            var document          = documentSnapshotSpan.Document;

            // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/763988
            // It turns out a document might be associated with a project of wrong language, e.g. C# document in a Xaml project.
            // Even though we couldn't repro the crash above, a fix is made in one of possibly multiple code paths that could cause
            // us to end up in this situation.
            // Regardless of the effective of the fix, we want to enhance the guard against such scenario here until an audit in
            // workspace is completed to eliminate the root cause.
            if (document?.SupportsSyntaxTree != true)
            {
                return;
            }

            var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            if (!documentOptions.GetOption(FeatureOnOffOptions.KeywordHighlighting))
            {
                return;
            }

            if (!caretPosition.HasValue)
            {
                return;
            }

            var snapshotSpan = documentSnapshotSpan.SnapshotSpan;
            var position     = caretPosition.Value;
            var snapshot     = snapshotSpan.Snapshot;

            // See if the user is just moving their caret around in an existing tag.  If so, we don't
            // want to actually go recompute things.  Note: this only works for containment.  If the
            // user moves their caret to the end of a highlighted reference, we do want to recompute
            // as they may now be at the start of some other reference that should be highlighted instead.
            var existingTags = context.GetExistingContainingTags(new SnapshotPoint(snapshot, position));

            if (!existingTags.IsEmpty())
            {
                context.SetSpansTagged(SpecializedCollections.EmptyEnumerable <DocumentSnapshotSpan>());
                return;
            }

            using (Logger.LogBlock(FunctionId.Tagger_Highlighter_TagProducer_ProduceTags, cancellationToken))
                using (s_listPool.GetPooledObject(out var highlights))
                {
                    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    _highlightingService.AddHighlights(root, position, highlights, cancellationToken);

                    foreach (var span in highlights)
                    {
                        context.AddTag(new TagSpan <KeywordHighlightTag>(span.ToSnapshotSpan(snapshot), KeywordHighlightTag.Instance));
                    }
                }
        }
        protected override async Task ProduceTagsAsync(TaggerContext <KeywordHighlightTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition)
        {
            var cancellationToken = context.CancellationToken;
            var document          = documentSnapshotSpan.Document;

            if (document == null)
            {
                return;
            }

            var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            if (!documentOptions.GetOption(FeatureOnOffOptions.KeywordHighlighting))
            {
                return;
            }

            if (!caretPosition.HasValue)
            {
                return;
            }

            var snapshotSpan = documentSnapshotSpan.SnapshotSpan;
            var position     = caretPosition.Value;
            var snapshot     = snapshotSpan.Snapshot;

            // See if the user is just moving their caret around in an existing tag.  If so, we don't
            // want to actually go recompute things.  Note: this only works for containment.  If the
            // user moves their caret to the end of a highlighted reference, we do want to recompute
            // as they may now be at the start of some other reference that should be highlighted instead.
            var existingTags = context.GetExistingContainingTags(new SnapshotPoint(snapshot, position));

            if (!existingTags.IsEmpty())
            {
                context.SetSpansTagged(SpecializedCollections.EmptyEnumerable <DocumentSnapshotSpan>());
                return;
            }

            using (Logger.LogBlock(FunctionId.Tagger_Highlighter_TagProducer_ProduceTags, cancellationToken))
            {
                var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var spans = _highlightingService.GetHighlights(root, position, cancellationToken);
                foreach (var span in spans)
                {
                    context.AddTag(new TagSpan <KeywordHighlightTag>(span.ToSnapshotSpan(snapshot), KeywordHighlightTag.Instance));
                }
            }
        }
示例#3
0
        protected override Task ProduceTagsAsync(TaggerContext <NavigableHighlightTag> context)
        {
            // NOTE(cyrusn): Normally we'd limit ourselves to producing tags in the span we were
            // asked about.  However, we want to produce all tags here so that the user can actually
            // navigate between all of them using the appropriate tag navigation commands.  If we
            // don't generate all the tags then the user will cycle through an incorrect subset.
            if (context.CaretPosition == null)
            {
                return(Task.CompletedTask);
            }

            var caretPosition = context.CaretPosition.Value;

            if (!Workspace.TryGetWorkspace(caretPosition.Snapshot.AsText().Container, out var workspace))
            {
                return(Task.CompletedTask);
            }

            // GetSpansToTag may have produced no actual spans to tag.  Be resilient to that.
            var document = context.SpansToTag.FirstOrDefault(vt => vt.SnapshotSpan.Snapshot == caretPosition.Snapshot).Document;

            if (document == null)
            {
                return(Task.CompletedTask);
            }

            // Don't produce tags if the feature is not enabled.
            if (!workspace.Options.GetOption(FeatureOnOffOptions.ReferenceHighlighting, document.Project.Language))
            {
                return(Task.CompletedTask);
            }

            // See if the user is just moving their caret around in an existing tag.  If so, we don't
            // want to actually go recompute things.  Note: this only works for containment.  If the
            // user moves their caret to the end of a highlighted reference, we do want to recompute
            // as they may now be at the start of some other reference that should be highlighted instead.
            var existingTags = context.GetExistingContainingTags(caretPosition);

            if (!existingTags.IsEmpty())
            {
                context.SetSpansTagged(SpecializedCollections.EmptyEnumerable <DocumentSnapshotSpan>());
                return(Task.CompletedTask);
            }

            // Otherwise, we need to go produce all tags.
            return(ProduceTagsAsync(context, caretPosition, document));
        }