private static async Task ClassifySpansAsync(
            TaggerContext <IClassificationTag> context,
            DocumentSnapshotSpan spanToTag,
            IClassificationService classificationService,
            ClassificationTypeMap typeMap)
        {
            try
            {
                var document     = spanToTag.Document;
                var snapshotSpan = spanToTag.SnapshotSpan;
                var snapshot     = snapshotSpan.Snapshot;

                var cancellationToken = context.CancellationToken;
                using (Logger.LogBlock(FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags, cancellationToken))
                {
                    var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList();

                    await AddSemanticClassificationsAsync(
                        document, snapshotSpan.Span.ToTextSpan(), classificationService, classifiedSpans, cancellationToken : cancellationToken).ConfigureAwait(false);

                    ClassificationUtilities.Convert(typeMap, snapshotSpan.Snapshot, classifiedSpans, context.AddTag);
                    ClassificationUtilities.ReturnClassifiedSpanList(classifiedSpans);

                    var version = await document.Project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);

                    // Let the context know that this was the span we actually tried to tag.
                    context.SetSpansTagged(SpecializedCollections.SingletonEnumerable(spanToTag));
                    context.State = version;
                }
            }
            catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
        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));
                }
            }
        }
Example #4
0
        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 options = document.Project.Solution.Workspace.Options;

            if (!options.GetOption(FeatureOnOffOptions.KeywordHighlighting, document.Project.Language))
            {
                return;
            }

            if (!caretPosition.HasValue)
            {
                return;
            }

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

            var existingTags = context.GetExistingTags(new SnapshotSpan(snapshot, position, 0));

            if (!existingTags.IsEmpty())
            {
                // We already have a tag at this position.  So the user is moving from one highlight
                // tag to another.  In this case we don't want to recompute anything.  Let our caller
                // know that we should preserve all tags.
                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));
                }
            }
        }
Example #5
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));
        }
Example #6
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(SpecializedTasks.EmptyTask);
            }

            var caretPosition = context.CaretPosition.Value;

            Workspace workspace;

            if (!Workspace.TryGetWorkspace(caretPosition.Snapshot.AsText().Container, out workspace))
            {
                return(SpecializedTasks.EmptyTask);
            }

            var document = context.SpansToTag.First(vt => vt.SnapshotSpan.Snapshot == caretPosition.Snapshot).Document;

            if (document == null)
            {
                return(SpecializedTasks.EmptyTask);
            }

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

            var existingTags = context.GetExistingTags(new SnapshotSpan(caretPosition, 0));

            if (!existingTags.IsEmpty())
            {
                // We already have a tag at this position.  So the user is moving from one highlight
                // tag to another.  In this case we don't want to recompute anything.  Let our caller
                // know that we should preserve all tags.
                context.SetSpansTagged(SpecializedCollections.EmptyEnumerable <DocumentSnapshotSpan>());
                return(SpecializedTasks.EmptyTask);
            }

            // Otherwise, we need to go produce all tags.
            return(ProduceTagsAsync(context, caretPosition, workspace, document));
        }
        protected override async Task ProduceTagsAsync(TaggerContext <ITextMarkerTag> context)
        {
            Debug.Assert(context.SpansToTag.IsSingle());

            var spanToTag = context.SpansToTag.Single();

            var document = spanToTag.Document;

            if (document == null)
            {
                return;
            }

            var activeStatementTrackingService =
                document.Project.Solution.Workspace.Services.GetService <IActiveStatementTrackingService>();

            if (activeStatementTrackingService == null)
            {
                return;
            }

            var snapshot = spanToTag.SnapshotSpan.Snapshot;

            var activeStatementSpans = await activeStatementTrackingService
                                       .GetAdjustedTrackingSpansAsync(document, snapshot, context.CancellationToken)
                                       .ConfigureAwait(false);

            foreach (var activeStatementSpan in activeStatementSpans)
            {
                if (activeStatementSpan.IsLeaf)
                {
                    continue;
                }

                var snapshotSpan = activeStatementSpan.Span.GetSpan(snapshot);
                if (snapshotSpan.OverlapsWith(spanToTag.SnapshotSpan))
                {
                    context.AddTag(
                        new TagSpan <ITextMarkerTag>(snapshotSpan, ActiveStatementTag.Instance)
                        );
                }
            }

            // Let the context know that this was the span we actually tried to tag.
            context.SetSpansTagged(SpecializedCollections.SingletonEnumerable(spanToTag));
        }
Example #8
0
        private static async Task ClassifySpansAsync(
            TaggerContext <IClassificationTag> context,
            DocumentSnapshotSpan spanToTag,
            IClassificationService classificationService,
            ClassificationTypeMap typeMap,
            ClassificationOptions options,
            CancellationToken cancellationToken)
        {
            try
            {
                var document     = spanToTag.Document;
                var snapshotSpan = spanToTag.SnapshotSpan;
                var snapshot     = snapshotSpan.Snapshot;

                using (Logger.LogBlock(FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags, cancellationToken))
                {
                    using var _ = ArrayBuilder <ClassifiedSpan> .GetInstance(out var classifiedSpans);

                    await classificationService.AddSemanticClassificationsAsync(
                        document,
                        snapshotSpan.Span.ToTextSpan(),
                        options,
                        classifiedSpans,
                        cancellationToken).ConfigureAwait(false);

                    foreach (var span in classifiedSpans)
                    {
                        context.AddTag(ClassificationUtilities.Convert(typeMap, snapshotSpan.Snapshot, span));
                    }

                    var version = await document.Project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);

                    // Let the context know that this was the span we actually tried to tag.
                    context.SetSpansTagged(SpecializedCollections.SingletonEnumerable(spanToTag));
                    context.State = version;
                }
            }
            catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
        private static async Task ClassifySpansAsync(TaggerContext<IClassificationTag> context, DocumentSnapshotSpan spanToTag,
            IEditorClassificationService classificationService, ClassificationTypeMap typeMap)
        {
            try
            {
                var document = spanToTag.Document;
                var snapshotSpan = spanToTag.SnapshotSpan;
                var snapshot = snapshotSpan.Snapshot;

                var cancellationToken = context.CancellationToken;
                using (Logger.LogBlock(FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags, cancellationToken))
                {
                    var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList();

                    await classificationService.AddSemanticClassificationsAsync(
                        document, snapshotSpan.Span.ToTextSpan(), classifiedSpans, cancellationToken: cancellationToken).ConfigureAwait(false);

                    ClassificationUtilities.Convert(typeMap, snapshotSpan.Snapshot, classifiedSpans, context.AddTag);
                    ClassificationUtilities.ReturnClassifiedSpanList(classifiedSpans);

                    var version = await document.Project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);

                    // Let the context know that this was the span we actually tried to tag.
                    context.SetSpansTagged(SpecializedCollections.SingletonEnumerable(spanToTag));
                    context.State = version;
                }
            }
            catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }