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)); }
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; } }
public IEnumerable <ITagSpan <IClassificationTag> > GetTags(NormalizedSnapshotSpanCollection spans) { using (Logger.LogBlock(FunctionId.Tagger_SyntacticClassification_TagComputer_GetTags, CancellationToken.None)) { if (spans.Count > 0 && _workspace != null) { var firstSpan = spans[0]; var languageServices = _workspace.Services.GetLanguageServices(firstSpan.Snapshot.ContentType); if (languageServices != null) { var classificationService = languageServices.GetService <IEditorClassificationService>(); if (classificationService != null) { var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList(); foreach (var span in spans) { AddClassifiedSpans(classificationService, span, classifiedSpans); } return(ClassificationUtilities.ConvertAndReturnList(_typeMap, spans[0].Snapshot, classifiedSpans)); } } } return(SpecializedCollections.EmptyEnumerable <ITagSpan <IClassificationTag> >()); } }
private void Clear() { lock (_gate) { _span = default; ClassificationUtilities.ReturnClassifiedSpanList(_classifications); _classifications = null; } }
protected sealed override Task ProduceTagsAsync( TaggerContext <IClassificationTag> context, CancellationToken cancellationToken) { Debug.Assert(context.SpansToTag.IsSingle()); var spanToTag = context.SpansToTag.Single(); var document = spanToTag.Document; if (document == null) { return(Task.CompletedTask); } // Attempt to get a classification service which will actually produce the results. // If we can't (because we have no Document, or because the language doesn't support // this service), then bail out immediately. var classificationService = document.GetLanguageService <IClassificationService>(); if (classificationService == null) { return(Task.CompletedTask); } // The LSP client will handle producing tags when running under the LSP editor. // Our tagger implementation should return nothing to prevent conflicts. var workspaceContextService = document.Project.Solution.Workspace.Services.GetRequiredService <IWorkspaceContextService>(); if (workspaceContextService?.IsInLspEditorContext() == true) { return(Task.CompletedTask); } // If the LSP semantic tokens feature flag is enabled, return nothing to prevent conflicts. var isLspSemanticTokensEnabled = _globalOptions.GetOption(LspOptions.LspSemanticTokensFeatureFlag); if (isLspSemanticTokensEnabled) { return(Task.CompletedTask); } var classificationOptions = _globalOptions.GetClassificationOptions(document.Project.Language); return(ClassificationUtilities.ProduceTagsAsync( context, spanToTag, classificationService, _typeMap, classificationOptions, _type, cancellationToken)); }
private void AddClassifiedSpansForCurrentTree( IEditorClassificationService classificationService, SnapshotSpan span, Document document, List <ClassifiedSpan> classifiedSpans) { if (!_lastLineCache.TryUseCache(span, out var tempList)) { tempList = ClassificationUtilities.GetOrCreateClassifiedSpanList(); classificationService.AddSyntacticClassificationsAsync( document, span.Span.ToTextSpan(), tempList, CancellationToken.None).Wait(CancellationToken.None); _lastLineCache.Update(span, tempList); } // simple case. They're asking for the classifications for a tree that we already have. // Just get the results from the tree and return them. classifiedSpans.AddRange(tempList); }
public override async Task <IEnumerable <ITagSpan <IClassificationTag> > > ProduceTagsAsync( Document document, SnapshotSpan snapshotSpan, int?caretPosition, CancellationToken cancellationToken) { try { var snapshot = snapshotSpan.Snapshot; if (document == null) { return(SpecializedCollections.EmptyEnumerable <ITagSpan <IClassificationTag> >()); } if (_classificationService == null) { _classificationService = document.Project.LanguageServices.GetService <IEditorClassificationService>(); } if (_classificationService == null) { return(SpecializedCollections.EmptyEnumerable <ITagSpan <IClassificationTag> >()); } // we don't directly reference the semantic model here, we just keep it alive so // the classification service does not need to block to produce it. using (Logger.LogBlock(FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags, cancellationToken)) { var textSpan = snapshotSpan.Span.ToTextSpan(); var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList(); await _classificationService.AddSemanticClassificationsAsync( document, textSpan, classifiedSpans, cancellationToken : cancellationToken).ConfigureAwait(false); return(ClassificationUtilities.ConvertAndReturnList(_typeMap, snapshotSpan.Snapshot, classifiedSpans)); } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private IEnumerable <ITagSpan <IClassificationTag> > GetTagsWorker(NormalizedSnapshotSpanCollection spans) { var classificationService = TryGetClassificationService(spans[0].Snapshot); if (classificationService == null) { return(null); } var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList(); foreach (var span in spans) { AddClassifiedSpans(classificationService, span, classifiedSpans); } return(ClassificationUtilities.ConvertAndReturnList( _typeMap, spans[0].Snapshot, classifiedSpans)); }
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; } }
public IEnumerable <ITagSpan <IClassificationTag> > GetTags(NormalizedSnapshotSpanCollection spans) { using (Logger.LogBlock(FunctionId.Tagger_SyntacticClassification_TagComputer_GetTags, CancellationToken.None)) { if (!_cachedTaggableStatus.HasValue) { if (!_isClassificationOnlyWorkspace) { _cachedTaggableStatus = true; } else { var wpfTextViews = _associatedViewService.GetAssociatedTextViews(_subjectBuffer); if (wpfTextViews.Any()) { _cachedTaggableStatus = _viewSupportsClassificationServiceOpt?.CanClassifyViews(wpfTextViews.Cast <ITextView>()) ?? true; } } } if (_cachedTaggableStatus == false) { return(SpecializedCollections.EmptyEnumerable <ITagSpan <IClassificationTag> >()); } if (spans.Count > 0) { var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList(); foreach (var span in spans) { AddClassifiedSpans(_editorClassificationService, span, classifiedSpans); } return(ClassificationUtilities.ConvertAndReturnList(_typeMap, spans[0].Snapshot, classifiedSpans)); } return(SpecializedCollections.EmptyEnumerable <ITagSpan <IClassificationTag> >()); } }
private IEnumerable <ITagSpan <IClassificationTag> > GetTags <TClassificationService>( NormalizedSnapshotSpanCollection spans, HostLanguageServices languageServices, IClassificationDelegationService <TClassificationService> delegationService) where TClassificationService : class, ILanguageService { var classificationService = languageServices.GetService <TClassificationService>(); if (classificationService == null) { return(null); } var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList(); foreach (var span in spans) { AddClassifiedSpans(delegationService, classificationService, span, classifiedSpans); } return(ClassificationUtilities.ConvertAndReturnList( _typeMap, spans[0].Snapshot, classifiedSpans)); }
private void AddClassifiedSpansForPreviousTree( IEditorClassificationService classificationService, SnapshotSpan span, ITextSnapshot lastSnapshot, Document lastDocument, List <ClassifiedSpan> classifiedSpans) { // Slightly more complicated case. They're asking for the classifications for a // different snapshot than what we have a parse tree for. So we first translate the span // that they're asking for so that is maps onto the tree that we have spans for. We then // get the classifications from that tree. We then take the results and translate them // back to the snapshot they want. Finally, as some of the classifications may have // changed, we check for some common cases and touch them up manually so that things // look right for the user. // Note the handling of SpanTrackingModes here: We do EdgeExclusive while mapping back , // and EdgeInclusive mapping forward. What I've convinced myself is that EdgeExclusive // is best when mapping back over a deletion, so that we don't end up classifying all of // the deleted code. In most addition/modification cases, there will be overlap with // existing spans, and so we'll end up classifying well. In the worst case, there is a // large addition that doesn't exist when we map back, and so we don't have any // classifications for it. That's probably okay, because: // 1. If it's that large, it's likely that in reality there are multiple classification // spans within it. // 2.We'll eventually call ClassificationsChanged and re-classify that region anyway. // When mapping back forward, we use EdgeInclusive so that in the common typing cases we // don't end up with half a token colored differently than the other half. // See bugs like http://vstfdevdiv:8080/web/wi.aspx?id=6176 for an example of what can // happen when this goes wrong. // 1) translate the requested span onto the right span for the snapshot that corresponds // to the syntax tree. var translatedSpan = span.TranslateTo(lastSnapshot, SpanTrackingMode.EdgeExclusive); if (translatedSpan.IsEmpty) { // well, there is no information we can get from previous tree, use lexer to // classify given span. soon we will re-classify the region. AddClassifiedSpansForTokens(classificationService, span, classifiedSpans); return; } var tempList = ClassificationUtilities.GetOrCreateClassifiedSpanList(); AddClassifiedSpansForCurrentTree(classificationService, translatedSpan, lastDocument, tempList); var currentSnapshot = span.Snapshot; var currentText = currentSnapshot.AsText(); foreach (var lastClassifiedSpan in tempList) { // 2) Translate those classifications forward so that they correspond to the true // requested snapshot. var lastSnapshotSpan = lastClassifiedSpan.TextSpan.ToSnapshotSpan(lastSnapshot); var currentSnapshotSpan = lastSnapshotSpan.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeInclusive); var currentClassifiedSpan = new ClassifiedSpan(lastClassifiedSpan.ClassificationType, currentSnapshotSpan.Span.ToTextSpan()); // 3) The classifications may be incorrect due to changes in the text. For example, // if "clss" becomes "class", then we want to changes the classification from // 'identifier' to 'keyword'. currentClassifiedSpan = classificationService.AdjustStaleClassification(currentText, currentClassifiedSpan); classifiedSpans.Add(currentClassifiedSpan); } ClassificationUtilities.ReturnClassifiedSpanList(tempList); }