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