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> >());
                }
            }
Esempio n. 4
0
 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));
            }
Esempio n. 9
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;
            }
        }
Esempio n. 10
0
            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);
            }