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 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; } }
private static async Task AddSemanticClassificationsAsync( Document document, TextSpan textSpan, IClassificationService classificationService, ArrayBuilder <ClassifiedSpan> classifiedSpans, CancellationToken cancellationToken) { var workspaceStatusService = document.Project.Solution.Workspace.Services.GetRequiredService <IWorkspaceStatusService>(); // Importantly, we do not await/wait on the fullyLoadedStateTask. We do not want to ever be waiting on work // that may end up touching the UI thread (As we can deadlock if GetTagsSynchronous waits on us). Instead, // we only check if the Task is completed. Prior to that we will assume we are still loading. Once this // task is completed, we know that the WaitUntilFullyLoadedAsync call will have actually finished and we're // fully loaded. var isFullyLoadedTask = workspaceStatusService.IsFullyLoadedAsync(cancellationToken); var isFullyLoaded = isFullyLoadedTask.IsCompleted && isFullyLoadedTask.GetAwaiter().GetResult(); // If we're not fully loaded try to read from the cache instead so that classifications appear up to date. // New code will not be semantically classified, but will eventually when the project fully loads. if (await TryAddSemanticClassificationsFromCacheAsync(document, textSpan, classifiedSpans, isFullyLoaded, cancellationToken).ConfigureAwait(false)) { return; } await classificationService.AddSemanticClassificationsAsync( document, textSpan, classifiedSpans, cancellationToken).ConfigureAwait(false); }
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 AddSemanticClassificationsAsync( Document document, TextSpan textSpan, IClassificationService classificationService, List <ClassifiedSpan> classifiedSpans, CancellationToken cancellationToken) { // Note: we do this work in a Task.Run to ensure that nothing we do (sync or async) ends up causing blocking // on the UI thread inside of IWorkspaceStatusService. This is necessary as synchronous tagging will cause // us to make an explicit .Wait call on the tagging tasks. If this thread in any way ended up blocking on // the UI thread, we would deadlock. var fullyLoadedStateTask = s_workspaceToFullyLoadedStateTask.GetValue( document.Project.Solution.Workspace, w => Task.Run(async() => { var workspaceLoadedService = w.Services.GetRequiredService <IWorkspaceStatusService>(); await workspaceLoadedService.WaitUntilFullyLoadedAsync(CancellationToken.None).ConfigureAwait(false); })); // If we're not fully loaded try to read from the cache instead so that classifications appear up to date. // New code will not be semantically classified, but will eventually when the project fully loads. // // Importantly, we do not await/wait on the fullyLoadedStateTask. We do not want to ever be waiting on work // that may end up touching the UI thread (As we can deadlock if GetTagsSynchronous waits on us). Instead, // we only check if the Task is completed. Prior to that we will assume we are still loading. Once this // task is completed, we know that the WaitUntilFullyLoadedAsync call will have actually finished and we're // fully loaded. var isFullyLoaded = fullyLoadedStateTask.IsCompleted; if (await TryAddSemanticClassificationsFromCacheAsync(document, textSpan, classifiedSpans, isFullyLoaded, cancellationToken).ConfigureAwait(false)) { return; } await classificationService.AddSemanticClassificationsAsync( document, textSpan, classifiedSpans, cancellationToken).ConfigureAwait(false); }
private static async Task AddClassificationsAsync( IClassificationService classificationService, ClassificationOptions options, Document document, SnapshotSpan snapshotSpan, ArrayBuilder <ClassifiedSpan> classifiedSpans, ClassificationType type, CancellationToken cancellationToken) { if (type == ClassificationType.Semantic) { await classificationService.AddSemanticClassificationsAsync( document, snapshotSpan.Span.ToTextSpan(), options, classifiedSpans, cancellationToken).ConfigureAwait(false); } else if (type == ClassificationType.EmbeddedLanguage) { await classificationService.AddEmbeddedLanguageClassificationsAsync( document, snapshotSpan.Span.ToTextSpan(), options, classifiedSpans, cancellationToken).ConfigureAwait(false); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public async Task AddSemanticClassificationsAsync(Document document, TextSpan textSpan, List <ClassifiedSpan> result, CancellationToken cancellationToken) => await _originalService.AddSemanticClassificationsAsync(document, textSpan, result, cancellationToken).ConfigureAwait(false);
protected override async Task AddClassificationsAsync(IClassificationService classificationService, Document document, TextSpan textSpan, List <ClassifiedSpan> spans, CancellationToken cancellationToken) => await classificationService.AddSemanticClassificationsAsync(document, textSpan, spans, cancellationToken).ConfigureAwait(false);