public async Task AddEmbeddedLanguageClassificationsAsync( Document document, TextSpan textSpan, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); AddEmbeddedLanguageClassifications(document.Project, semanticModel, textSpan, options, result, cancellationToken); }
internal static IEnumerable <ClassifiedSpan> GetClassifiedSpans( HostWorkspaceServices workspaceServices, SemanticModel semanticModel, TextSpan textSpan, ClassificationOptions options, CancellationToken cancellationToken) { var service = workspaceServices.GetLanguageServices(semanticModel.Language).GetRequiredService <ISyntaxClassificationService>(); var syntaxClassifiers = service.GetDefaultSyntaxClassifiers(); var extensionManager = workspaceServices.GetRequiredService <IExtensionManager>(); var getNodeClassifiers = extensionManager.CreateNodeExtensionGetter(syntaxClassifiers, c => c.SyntaxNodeTypes); var getTokenClassifiers = extensionManager.CreateTokenExtensionGetter(syntaxClassifiers, c => c.SyntaxTokenKinds); using var _1 = ArrayBuilder <ClassifiedSpan> .GetInstance(out var syntacticClassifications); using var _2 = ArrayBuilder <ClassifiedSpan> .GetInstance(out var semanticClassifications); var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); service.AddSyntacticClassifications(root, textSpan, syntacticClassifications, cancellationToken); service.AddSemanticClassifications(semanticModel, textSpan, getNodeClassifiers, getTokenClassifiers, semanticClassifications, options, cancellationToken); var allClassifications = new List <ClassifiedSpan>(semanticClassifications.Where(s => s.TextSpan.OverlapsWith(textSpan))); var semanticSet = semanticClassifications.Select(s => s.TextSpan).ToSet(); allClassifications.AddRange(syntacticClassifications.Where( s => s.TextSpan.OverlapsWith(textSpan) && !semanticSet.Contains(s.TextSpan))); allClassifications.Sort((s1, s2) => s1.TextSpan.Start - s2.TextSpan.Start); return(allClassifications); }
private Task ProduceTagsAsync( TaggerContext <IClassificationTag> context, DocumentSnapshotSpan snapshotSpan, IClassificationService classificationService, ClassificationOptions options, ClassificationType type, CancellationToken cancellationToken) { return(ClassificationUtilities.ProduceTagsAsync( context, snapshotSpan, classificationService, _owner._typeMap, options, type, cancellationToken)); }
public void AddSemanticClassifications( SemanticModel semanticModel, TextSpan textSpan, Func <SyntaxNode, ImmutableArray <ISyntaxClassifier> > getNodeClassifiers, Func <SyntaxToken, ImmutableArray <ISyntaxClassifier> > getTokenClassifiers, ArrayBuilder <ClassifiedSpan> result, ClassificationOptions options, CancellationToken cancellationToken) { Worker.Classify(semanticModel, textSpan, result, getNodeClassifiers, getTokenClassifiers, options, cancellationToken); }
public static async Task <IEnumerable <ClassifiedSpan> > GetClassifiedSpansAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken = default) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var options = ClassificationOptions.From(document.Project); return(GetClassifiedSpans(document.Project.Solution.Workspace.Services, semanticModel, textSpan, options, cancellationToken)); }
public static async Task <DocumentSpan> GetClassifiedDocumentSpanAsync( Document document, TextSpan sourceSpan, ClassificationOptions options, CancellationToken cancellationToken) { var classifiedSpans = await ClassifyAsync( document, sourceSpan, options, cancellationToken).ConfigureAwait(false); var properties = ImmutableDictionary <string, object> .Empty.Add( ClassifiedSpansAndHighlightSpan.Key, classifiedSpans); return(new DocumentSpan(document, sourceSpan, properties)); }
private static async Task <ClassifiedSpansAndHighlightSpan> GetTaggedTextForDocumentRegionAsync( Document document, TextSpan narrowSpan, TextSpan widenedSpan, ClassificationOptions options, CancellationToken cancellationToken) { var highlightSpan = new TextSpan( start: narrowSpan.Start - widenedSpan.Start, length: narrowSpan.Length); var classifiedSpans = await GetClassifiedSpansAsync( document, narrowSpan, widenedSpan, options, cancellationToken).ConfigureAwait(false); return(new ClassifiedSpansAndHighlightSpan(classifiedSpans, highlightSpan)); }
/// <summary> /// Classifies the provided <paramref name="span"/> in the given <paramref name="document"/>. /// This will do this using an appropriate <see cref="IClassificationService"/> /// if that can be found. <see cref="ImmutableArray{T}.IsDefault"/> will be returned if this /// fails. /// </summary> public static async Task <ImmutableArray <ClassifiedSpan> > GetClassifiedSpansAsync( Document document, TextSpan span, ClassificationOptions options, CancellationToken cancellationToken, bool removeAdditiveSpans = true, bool fillInClassifiedSpanGaps = true) { var classificationService = document.GetLanguageService <IClassificationService>(); if (classificationService == null) { return(default);
public void AddEmbeddedLanguageClassifications( Project?project, SemanticModel semanticModel, TextSpan textSpan, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { if (project is null) { return; } var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); var worker = new Worker(this, project, semanticModel, textSpan, options, result, cancellationToken); worker.Recurse(root); }
private static async Task <ClassifiedSpansAndHighlightSpan> ClassifyAsync( Document document, TextSpan sourceSpan, ClassificationOptions options, CancellationToken cancellationToken) { var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var narrowSpan = sourceSpan; var lineSpan = GetLineSpanForReference(sourceText, narrowSpan); var taggedLineParts = await GetTaggedTextForDocumentRegionAsync( document, narrowSpan, lineSpan, options, cancellationToken).ConfigureAwait(false); return(taggedLineParts); }
internal EmbeddedLanguageClassificationContext( SemanticModel semanticModel, SyntaxToken syntaxToken, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { SemanticModel = semanticModel; SyntaxToken = syntaxToken; Options = options; _result = result; CancellationToken = cancellationToken; }
public static async Task <ClassifiedSpansAndHighlightSpan> ClassifyAsync( DocumentSpan documentSpan, ClassificationOptions options, CancellationToken cancellationToken) { // If the document span is providing us with the classified spans up front, then we // can just use that. Otherwise, go back and actually classify the text for the line // the document span is on. if (documentSpan.Properties != null && documentSpan.Properties.TryGetValue(ClassifiedSpansAndHighlightSpan.Key, out var value)) { return((ClassifiedSpansAndHighlightSpan)value); } return(await ClassifyAsync( documentSpan.Document, documentSpan.SourceSpan, options, cancellationToken).ConfigureAwait(false)); }
internal EmbeddedLanguageClassificationContext( Project project, SemanticModel semanticModel, SyntaxToken syntaxToken, ClassificationOptions options, IVirtualCharService virtualCharService, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { Project = project; SemanticModel = semanticModel; SyntaxToken = syntaxToken; Options = options; VirtualCharService = virtualCharService; _result = result; CancellationToken = cancellationToken; }
public static async Task AddClassificationsInCurrentProcessAsync( Document document, TextSpan textSpan, ClassificationType type, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { if (type == ClassificationType.Semantic) { var classificationService = document.GetRequiredLanguageService <ISyntaxClassificationService>(); var reassignedVariableService = document.GetRequiredLanguageService <IReassignedVariableService>(); var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService <IExtensionManager>(); var classifiers = classificationService.GetDefaultSyntaxClassifiers(); var getNodeClassifiers = extensionManager.CreateNodeExtensionGetter(classifiers, c => c.SyntaxNodeTypes); var getTokenClassifiers = extensionManager.CreateTokenExtensionGetter(classifiers, c => c.SyntaxTokenKinds); await classificationService.AddSemanticClassificationsAsync( document, textSpan, options, getNodeClassifiers, getTokenClassifiers, result, cancellationToken).ConfigureAwait(false); if (options.ClassifyReassignedVariables) { var reassignedVariableSpans = await reassignedVariableService.GetLocationsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); foreach (var span in reassignedVariableSpans) { result.Add(new ClassifiedSpan(span, ClassificationTypeNames.ReassignedVariable)); } } } else if (type == ClassificationType.EmbeddedLanguage) { var embeddedLanguageService = document.GetLanguageService <IEmbeddedLanguageClassificationService>(); if (embeddedLanguageService != null) { await embeddedLanguageService.AddEmbeddedLanguageClassificationsAsync( document, textSpan, options, result, cancellationToken).ConfigureAwait(false); } } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public Worker( AbstractEmbeddedLanguageClassificationService service, Project project, SemanticModel semanticModel, TextSpan textSpan, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { _owner = service; _project = project; _semanticModel = semanticModel; _textSpan = textSpan; _options = options; _result = result; _cancellationToken = cancellationToken; }
public static async Task ProduceTagsAsync( TaggerContext <IClassificationTag> context, DocumentSnapshotSpan spanToTag, IClassificationService classificationService, ClassificationTypeMap typeMap, ClassificationOptions options, ClassificationType type, CancellationToken cancellationToken) { var document = spanToTag.Document; if (document == null) { return; } // Don't block getting classifications on building the full compilation. This may take a significant amount // of time and can cause a very latency sensitive operation (copying) to block the user while we wait on this // work to happen. // // It's also a better experience to get classifications to the user faster versus waiting a potentially // large amount of time waiting for all the compilation information to be built. For example, we can // classify types that we've parsed in other files, or partially loaded from metadata, even if we're still // parsing/loading. For cross language projects, this also produces semantic classifications more quickly // as we do not have to wait on skeletons to be built. document = document.WithFrozenPartialSemantics(cancellationToken); options = options with { ForceFrozenPartialSemanticsForCrossProcessOperations = true }; var classified = await TryClassifyContainingMemberSpanAsync( context, document, spanToTag.SnapshotSpan, classificationService, typeMap, options, type, cancellationToken).ConfigureAwait(false); if (classified) { return; } // We weren't able to use our specialized codepaths for semantic classifying. // Fall back to classifying the full span that was asked for. await ClassifySpansAsync( context, document, spanToTag.SnapshotSpan, classificationService, typeMap, options, type, cancellationToken).ConfigureAwait(false); }
private static async Task <ImmutableArray <ClassifiedSpan> > GetClassifiedSpansAsync( Document document, TextSpan narrowSpan, TextSpan widenedSpan, ClassificationOptions options, CancellationToken cancellationToken) { var result = await ClassifierHelper.GetClassifiedSpansAsync( document, widenedSpan, options, cancellationToken).ConfigureAwait(false); if (!result.IsDefault) { return(result); } // For languages that don't expose a classification service, we show the entire // item as plain text. Break the text into three spans so that we can properly // highlight the 'narrow-span' later on when we display the item. return(ImmutableArray.Create( new ClassifiedSpan(ClassificationTypeNames.Text, TextSpan.FromBounds(widenedSpan.Start, narrowSpan.Start)), new ClassifiedSpan(ClassificationTypeNames.Text, narrowSpan), new ClassifiedSpan(ClassificationTypeNames.Text, TextSpan.FromBounds(narrowSpan.End, widenedSpan.End)))); }
public async Task AddSemanticClassificationsAsync( Document document, TextSpan textSpan, ClassificationOptions options, Func <SyntaxNode, ImmutableArray <ISyntaxClassifier> > getNodeClassifiers, Func <SyntaxToken, ImmutableArray <ISyntaxClassifier> > getTokenClassifiers, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { try { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); AddSemanticClassifications(semanticModel, textSpan, getNodeClassifiers, getTokenClassifiers, result, options, cancellationToken); } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } }
private Worker( SemanticModel semanticModel, TextSpan textSpan, ArrayBuilder <ClassifiedSpan> list, Func <SyntaxNode, ImmutableArray <ISyntaxClassifier> > getNodeClassifiers, Func <SyntaxToken, ImmutableArray <ISyntaxClassifier> > getTokenClassifiers, ClassificationOptions options, CancellationToken cancellationToken) { _getNodeClassifiers = getNodeClassifiers; _getTokenClassifiers = getTokenClassifiers; _semanticModel = semanticModel; _syntaxTree = semanticModel.SyntaxTree; _textSpan = textSpan; _list = list; _cancellationToken = cancellationToken; _options = options; // get one from pool _set = SharedPools.Default <HashSet <ClassifiedSpan> >().AllocateAndClear(); _pendingNodes = SharedPools.Default <Stack <SyntaxNodeOrToken> >().AllocateAndClear(); }
internal static void Classify( SemanticModel semanticModel, TextSpan textSpan, ArrayBuilder <ClassifiedSpan> list, Func <SyntaxNode, ImmutableArray <ISyntaxClassifier> > getNodeClassifiers, Func <SyntaxToken, ImmutableArray <ISyntaxClassifier> > getTokenClassifiers, ClassificationOptions options, CancellationToken cancellationToken) { var worker = new Worker(semanticModel, textSpan, list, getNodeClassifiers, getTokenClassifiers, options, cancellationToken); try { worker._pendingNodes.Push(worker._syntaxTree.GetRoot(cancellationToken)); worker.ProcessNodes(); } finally { // release collections to the pool SharedPools.Default <HashSet <ClassifiedSpan> >().ClearAndFree(worker._set); SharedPools.Default <Stack <SyntaxNodeOrToken> >().ClearAndFree(worker._pendingNodes); } }
private static async Task ClassifySpansAsync( TaggerContext <IClassificationTag> context, Document document, SnapshotSpan snapshotSpan, IClassificationService classificationService, ClassificationTypeMap typeMap, ClassificationOptions options, ClassificationType type, CancellationToken cancellationToken) { try { using (Logger.LogBlock(FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags, cancellationToken)) { using var _ = ArrayBuilder <ClassifiedSpan> .GetInstance(out var classifiedSpans); await AddClassificationsAsync( classificationService, options, document, snapshotSpan, classifiedSpans, type, cancellationToken).ConfigureAwait(false); foreach (var span in classifiedSpans) { context.AddTag(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(ImmutableArray.Create(snapshotSpan)); context.State = version; } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } }
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); } }
private static async Task <bool> TryClassifyContainingMemberSpanAsync( TaggerContext <IClassificationTag> context, Document document, SnapshotSpan snapshotSpan, IClassificationService classificationService, ClassificationTypeMap typeMap, ClassificationOptions options, ClassificationType type, CancellationToken cancellationToken) { var range = context.TextChangeRange; if (range == null) { // There was no text change range, we can't just reclassify a member body. return(false); } // there was top level edit, check whether that edit updated top level element if (!document.SupportsSyntaxTree) { return(false); } var lastSemanticVersion = (VersionStamp?)context.State; if (lastSemanticVersion != null) { var currentSemanticVersion = await document.Project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false); if (lastSemanticVersion.Value != currentSemanticVersion) { // A top level change was made. We can't perform this optimization. return(false); } } var service = document.GetRequiredLanguageService <ISyntaxFactsService>(); // perf optimization. Check whether all edits since the last update has happened within // a member. If it did, it will find the member that contains the changes and only refresh // that member. If possible, try to get a speculative binder to make things even cheaper. var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var changedSpan = new TextSpan(range.Value.Span.Start, range.Value.NewLength); var member = service.GetContainingMemberDeclaration(root, changedSpan.Start); if (member == null || !member.FullSpan.Contains(changedSpan)) { // The edit was not fully contained in a member. Reclassify everything. return(false); } var subTextSpan = service.GetMemberBodySpanForSpeculativeBinding(member); if (subTextSpan.IsEmpty) { // Wasn't a member we could reclassify independently. return(false); } var subSpanToTag = new SnapshotSpan( snapshotSpan.Snapshot, subTextSpan.Contains(changedSpan) ? subTextSpan.ToSpan() : member.FullSpan.ToSpan()); // re-classify only the member we're inside. await ClassifySpansAsync( context, document, subSpanToTag, classificationService, typeMap, options, type, cancellationToken).ConfigureAwait(false); return(true); }
public Task AddSemanticClassificationsAsync( Document document, TextSpan textSpan, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { return(AddClassificationsAsync(document, textSpan, options, ClassificationType.Semantic, result, cancellationToken)); }
internal static async Task <ImmutableArray <SymbolDisplayPart> > GetClassifiedSymbolDisplayPartsAsync( HostWorkspaceServices workspaceServices, SemanticModel semanticModel, TextSpan textSpan, ClassificationOptions options, CancellationToken cancellationToken = default) { var classifiedSpans = GetClassifiedSpans(workspaceServices, semanticModel, textSpan, options, cancellationToken); var sourceText = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); return(ConvertClassificationsToParts(sourceText, textSpan.Start, classifiedSpans)); }
public Task AddEmbeddedLanguageClassificationsAsync( Document document, TextSpan textSpan, ClassificationOptions options, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { return(AddClassificationsAsync(document, textSpan, options, ClassificationType.EmbeddedLanguage, result, cancellationToken)); }
public static IEnumerable <ClassifiedSpan> GetClassifiedSpans( SemanticModel semanticModel, TextSpan textSpan, Workspace workspace, CancellationToken cancellationToken = default) => GetClassifiedSpans(workspace.Services, semanticModel, textSpan, ClassificationOptions.From(workspace.CurrentSolution.Options, semanticModel.Language), cancellationToken);
private static async Task AddClassificationsAsync( Document document, TextSpan textSpan, ClassificationOptions options, ClassificationType type, ArrayBuilder <ClassifiedSpan> result, CancellationToken cancellationToken) { var classificationService = document.GetLanguageService <ISyntaxClassificationService>(); if (classificationService == null) { // When renaming a file's extension through VS when it's opened in editor, // the content type might change and the content type changed event can be // raised before the renaming propagate through VS workspace. As a result, // the document we got (based on the buffer) could still be the one in the workspace // before rename happened. This would cause us problem if the document is supported // by workspace but not a roslyn language (e.g. xaml, F#, etc.), since none of the roslyn // language services would be available. // // If this is the case, we will simply bail out. It's OK to ignore the request // because when the buffer eventually get associated with the correct document in roslyn // workspace, we will be invoked again. // // For example, if you open a xaml from from a WPF project in designer view, // and then rename file extension from .xaml to .cs, then the document we received // here would still belong to the special "-xaml" project. return; } var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); if (client != null) { // We have an oop connection. If we're not fully loaded, see if we can retrieve a previously cached set // of classifications from the server. Note: this must be a separate call (instead of being part of // service.GetSemanticClassificationsAsync below) as we want to try to read in the cached // classifications without doing any syncing to the OOP process. var isFullyLoaded = IsFullyLoaded(document, cancellationToken); if (await TryGetCachedClassificationsAsync(document, textSpan, type, client, isFullyLoaded, result, cancellationToken).ConfigureAwait(false)) { return; } // Call the project overload. Semantic classification only needs the current project's information // to classify properly. var classifiedSpans = await client.TryInvokeAsync <IRemoteSemanticClassificationService, SerializableClassifiedSpans>( document.Project, (service, solutionInfo, cancellationToken) => service.GetClassificationsAsync( solutionInfo, document.Id, textSpan, type, options, isFullyLoaded, cancellationToken), cancellationToken).ConfigureAwait(false); // if the remote call fails do nothing (error has already been reported) if (classifiedSpans.HasValue) { classifiedSpans.Value.Rehydrate(result); } } else { await AddClassificationsInCurrentProcessAsync( document, textSpan, type, options, result, cancellationToken).ConfigureAwait(false); } }