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));
 }
コード例 #2
0
        protected override async Task ProduceTagsAsync(TaggerContext <IStructureTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition)
        {
            var blockStructureProvider = spanToTag.Document.LanguageServices.GetService <IBlockStructureProvider>();

            if (blockStructureProvider == null)
            {
                return;
            }

            var blockSpans = await blockStructureProvider.ProvideBlockStructureAsync(spanToTag.Document, context.CancellationToken).ConfigureAwait(false);

            var snapshot = spanToTag.SnapshotSpan.Snapshot;

            foreach (var blockSpan in blockSpans)
            {
                if (!blockSpan.IsCollapsible)
                {
                    continue;
                }

                context.AddTag(snapshot.GetTagSpan(
                                   blockSpan.TextSpan.ToSpan(),
                                   new StructureTag(
                                       snapshot,
                                       blockSpan.TextSpan.ToSpan(),
                                       blockSpan.HintSpan.ToSpan(),
                                       isCollapsible: blockSpan.IsCollapsible,
                                       isDefaultCollapsed: blockSpan.IsDefaultCollapsed,
                                       type: GetStructureTagType(blockSpan.Type))));
            }
        }
コード例 #3
0
        protected override async Task ProduceTagsAsync(TaggerContext <IOutliningRegionTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition)
        {
            var blockStructureProvider = spanToTag.Document.LanguageServices.GetService <IBlockStructureProvider>();

            if (blockStructureProvider == null)
            {
                return;
            }

            var blockSpans = await blockStructureProvider.ProvideBlockStructureAsync(spanToTag.Document, context.CancellationToken).ConfigureAwait(false);

            var snapshot = spanToTag.SnapshotSpan.Snapshot;

            foreach (var blockSpan in blockSpans)
            {
                if (!blockSpan.IsCollapsible)
                {
                    continue;
                }

                var collapsedHintForm = snapshot.GetText(blockSpan.HintSpan.ToSpan());

                context.AddTag(snapshot.GetTagSpan(
                                   blockSpan.TextSpan.ToSpan(),
                                   new OutliningRegionTag(false, blockSpan.AutoCollapse, blockSpan.BannerText, collapsedHintForm)));
            }
        }
コード例 #4
0
        protected override async Task ProduceTagsAsync(TaggerContext <IClassificationTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition)
        {
            var document = spanToTag.Document;
            var classificationService = document?.LanguageServices.GetService <IClassificationService>();

            if (classificationService == null)
            {
                return;
            }

            Workspace.TryGetWorkspace(document.SourceText.Container, out var workspace);

            var semanticModel = await document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

            if (semanticModel == null)
            {
                return;
            }

            var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList();

            classificationService.AddSemanticClassifications(
                semanticModel,
                spanToTag.SnapshotSpan.Span.ToTextSpan(),
                workspace,
                classifiedSpans,
                context.CancellationToken);

            ClassificationUtilities.Convert(_typeMap, spanToTag.SnapshotSpan.Snapshot, classifiedSpans, context.AddTag);
            ClassificationUtilities.ReturnClassifiedSpanList(classifiedSpans);
        }
コード例 #5
0
        protected override async Task ProduceTagsAsync(TaggerContext <InlineHintDataTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition)
        {
            var cancellationToken = context.CancellationToken;
            var document          = documentSnapshotSpan.Document;
            var service           = document.GetLanguageService <IInlineHintsService>();

            if (service == null)
            {
                return;
            }

            var snapshotSpan = documentSnapshotSpan.SnapshotSpan;
            var hints        = await service.GetInlineHintsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false);

            foreach (var hint in hints)
            {
                // If we don't have any text to actually show the user, then don't make a tag.
                if (hint.DisplayParts.Sum(p => p.ToString().Length) == 0)
                {
                    continue;
                }

                context.AddTag(new TagSpan <InlineHintDataTag>(
                                   hint.Span.ToSnapshotSpan(snapshotSpan.Snapshot),
                                   new InlineHintDataTag(hint)));
            }
        }
コード例 #6
0
        internal async Task ProduceTagsAsync(
            TaggerContext <NavigableHighlightTag> context,
            SnapshotPoint position,
            Document document)
        {
            var cancellationToken = context.CancellationToken;

            var solution = document.Project.Solution;

            using (Logger.LogBlock(FunctionId.Tagger_ReferenceHighlighting_TagProducer_ProduceTags, cancellationToken))
            {
                if (document != null)
                {
                    var service = document.GetLanguageService <IDocumentHighlightsService>();
                    if (service != null)
                    {
                        // We only want to search inside documents that correspond to the snapshots
                        // we're looking at
                        var documentsToSearch      = ImmutableHashSet.CreateRange(context.SpansToTag.Select(vt => vt.Document).WhereNotNull());
                        var documentHighlightsList = await service.GetDocumentHighlightsAsync(
                            document, position, documentsToSearch, cancellationToken).ConfigureAwait(false);

                        if (documentHighlightsList != null)
                        {
                            foreach (var documentHighlights in documentHighlightsList)
                            {
                                await AddTagSpansAsync(
                                    context, document.Project.Solution, documentHighlights).ConfigureAwait(false);
                            }
                        }
                    }
                }
            }
        }
コード例 #7
0
        private static void AddTagSpans(
            TaggerContext <NavigableHighlightTag> context,
            DocumentHighlights documentHighlights,
            CancellationToken cancellationToken)
        {
            var document = documentHighlights.Document;

            var textSnapshot = context.SpansToTag.FirstOrDefault(s => s.Document == document).SnapshotSpan.Snapshot;

            if (textSnapshot == null)
            {
                // There is no longer an editor snapshot for this document, so we can't care about the
                // results.
                return;
            }

            try
            {
                foreach (var span in documentHighlights.HighlightSpans)
                {
                    var tag = GetTag(span);
                    context.AddTag(new TagSpan <NavigableHighlightTag>(
                                       textSnapshot.GetSpan(Span.FromBounds(span.TextSpan.Start, span.TextSpan.End)), tag));
                }
            }
            catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken, ErrorSeverity.General))
            {
                // report NFW and continue.
                // also, rather than return partial results, return nothing
                context.ClearTags();
            }
        }
コード例 #8
0
        protected override async Task ProduceTagsAsync(TaggerContext <LineSeparatorTag> 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.LineSeparator))
            {
                return;
            }

            using (Logger.LogBlock(FunctionId.Tagger_LineSeparator_TagProducer_ProduceTags, cancellationToken))
            {
                var snapshotSpan         = documentSnapshotSpan.SnapshotSpan;
                var lineSeparatorService = document.Project.LanguageServices.GetService <ILineSeparatorService>();
                var lineSeparatorSpans   = await lineSeparatorService.GetLineSeparatorsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                foreach (var span in lineSeparatorSpans)
                {
                    context.AddTag(new TagSpan <LineSeparatorTag>(span.ToSnapshotSpan(snapshotSpan.Snapshot), LineSeparatorTag.Instance));
                }
            }
        }
コード例 #9
0
        private static async Task AddTagSpansAsync(
            TaggerContext <NavigableHighlightTag> context,
            DocumentHighlights documentHighlights)
        {
            var cancellationToken = context.CancellationToken;
            var document          = documentHighlights.Document;

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var textSnapshot = text.FindCorrespondingEditorTextSnapshot();

            if (textSnapshot == null)
            {
                // There is no longer an editor snapshot for this document, so we can't care about the
                // results.
                return;
            }

            try
            {
                foreach (var span in documentHighlights.HighlightSpans)
                {
                    var tag = GetTag(span);
                    context.AddTag(new TagSpan <NavigableHighlightTag>(
                                       textSnapshot.GetSpan(Span.FromBounds(span.TextSpan.Start, span.TextSpan.End)), tag));
                }
            }
            catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e))
            {
                // report NFW and continue.
                // also, rather than return partial results, return nothing
                context.ClearTags();
            }
        }
        protected sealed override async Task ProduceTagsAsync(
            TaggerContext <TRegionTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition)
        {
            try
            {
                var document = documentSnapshotSpan.Document;
                if (document == null)
                {
                    return;
                }

                // Let LSP handle producing tags in the cloud scenario
                if (documentSnapshotSpan.SnapshotSpan.Snapshot.TextBuffer.IsInLspEditorContext())
                {
                    return;
                }

                var outliningService = BlockStructureService.GetService(document);
                if (outliningService == null)
                {
                    return;
                }

                var blockStructure = await outliningService.GetBlockStructureAsync(
                    documentSnapshotSpan.Document, context.CancellationToken).ConfigureAwait(false);

                ProcessSpans(
                    context, documentSnapshotSpan.SnapshotSpan, outliningService,
                    blockStructure.Spans);
            }
            catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
コード例 #11
0
        /// <summary>
        /// Keep this in sync with <see cref="ProduceTagsAsync"/>
        /// </summary>
        protected sealed override void ProduceTagsSynchronously(
            TaggerContext <TRegionTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition)
        {
            try
            {
                var outliningService = TryGetService(context, documentSnapshotSpan);
                if (outliningService != null)
                {
                    var document          = documentSnapshotSpan.Document;
                    var cancellationToken = context.CancellationToken;

                    // Try to call through the synchronous service if possible. Otherwise, fallback
                    // and make a blocking call against the async service.

                    var blockStructure = outliningService.GetBlockStructure(document, cancellationToken);

                    ProcessSpans(
                        context, documentSnapshotSpan.SnapshotSpan, outliningService,
                        blockStructure.Spans);
                }
            }
            catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
コード例 #12
0
        protected async Task TestBraceHighlightingAsync(string markup, ParseOptions options = null)
        {
            using (var workspace = CreateWorkspace(markup, options))
            {
                WpfTestRunner.RequireWpfFact($"{nameof(AbstractBraceHighlightingTests)}.{nameof(TestBraceHighlightingAsync)} creates asynchronous taggers");

                var provider = new BraceHighlightingViewTaggerProvider(
                    GetBraceMatchingService(workspace),
                    workspace.GetService <IForegroundNotificationService>(),
                    AsynchronousOperationListenerProvider.NullProvider);

                var testDocument = workspace.Documents.First();
                var buffer       = testDocument.TextBuffer;
                var document     = buffer.CurrentSnapshot.GetRelatedDocumentsWithChanges().FirstOrDefault();
                var context      = new TaggerContext <BraceHighlightTag>(
                    document, buffer.CurrentSnapshot,
                    new SnapshotPoint(buffer.CurrentSnapshot, testDocument.CursorPosition.Value));
                await provider.ProduceTagsAsync_ForTestingPurposesOnly(context);

                var expectedHighlights = testDocument.SelectedSpans.Select(ts => ts.ToSpan()).OrderBy(s => s.Start).ToList();
                var actualHighlights   = context.tagSpans.Select(ts => ts.Span.Span).OrderBy(s => s.Start).ToList();

                Assert.Equal(expectedHighlights, actualHighlights);
            }
        }
コード例 #13
0
        protected override async TPL.Task ProduceTagsAsync(
            TaggerContext <IClassificationTag> taggerContext,
            DocumentSnapshotSpan snapshotSpan)
        {
            // We should check this at the call site.
            // This a safety check to make sure we do this when
            // we introduce a new call site.
            Debug.Assert(snapshotSpan.Document != null);

            var document          = snapshotSpan.Document;
            var cancellationToken = taggerContext.CancellationToken;

            var classificationService = document.Project.LanguageServices.GetService <IClassificationService>() as IRemoteClassificationService;

            if (classificationService == null)
            {
                return;
            }

            var classifiedSpans = ClassificationUtilities.GetOrCreateClassifiedSpanList();
            var tagSpan         = TextSpan.FromBounds(snapshotSpan.SnapshotSpan.Start, snapshotSpan.SnapshotSpan.End);
            await classificationService.AddRemoteSyntacticClassificationsAsync(document, tagSpan, classifiedSpans, cancellationToken).ConfigureAwait(false);

            ClassificationUtilities.Convert(_typeMap, snapshotSpan.SnapshotSpan.Snapshot, classifiedSpans, taggerContext.AddTag);
            ClassificationUtilities.ReturnClassifiedSpanList(classifiedSpans);
        }
コード例 #14
0
        private void ProcessSpans(
            TaggerContext <TRegionTag> context,
            SnapshotSpan snapshotSpan,
            BlockStructureService outliningService,
            ImmutableArray <BlockSpan> spans)
        {
            if (spans != null)
            {
                var snapshot = snapshotSpan.Snapshot;
                spans = GetMultiLineRegions(outliningService, spans, snapshot);

                // Create the outlining tags.
                var tagSpanStack = new Stack <TagSpan <TRegionTag> >();

                foreach (var region in spans)
                {
                    var spanToCollapse = new SnapshotSpan(snapshot, region.TextSpan.ToSpan());

                    while (tagSpanStack.Count > 0 &&
                           tagSpanStack.Peek().Span.End <= spanToCollapse.Span.Start)
                    {
                        tagSpanStack.Pop();
                    }

                    var parentTag = tagSpanStack.Count > 0 ? tagSpanStack.Peek() : null;
                    var tag       = CreateTag(parentTag?.Tag, snapshot, region);

                    var tagSpan = new TagSpan <TRegionTag>(spanToCollapse, tag);

                    context.AddTag(tagSpan);
                    tagSpanStack.Push(tagSpan);
                }
            }
        }
コード例 #15
0
        protected async Task TestBraceHighlightingAsync(string markup)
        {
            using (var workspace = await CreateWorkspaceAsync(markup))
            {
                WpfTestCase.RequireWpfFact($"{nameof(AbstractBraceHighlightingTests)}.{nameof(TestBraceHighlightingAsync)} creates asynchronous taggers");

                var provider = new BraceHighlightingViewTaggerProvider(
                    workspace.GetService<IBraceMatchingService>(),
                    workspace.GetService<IForegroundNotificationService>(),
                    AggregateAsynchronousOperationListener.EmptyListeners);

                var testDocument = workspace.Documents.First();
                var buffer = testDocument.TextBuffer;
                var document = buffer.CurrentSnapshot.GetRelatedDocumentsWithChanges().FirstOrDefault();
                var context = new TaggerContext<BraceHighlightTag>(
                    document, buffer.CurrentSnapshot,
                    new SnapshotPoint(buffer.CurrentSnapshot, testDocument.CursorPosition.Value));
                await provider.ProduceTagsAsync_ForTestingPurposesOnly(context);

                var expectedHighlights = testDocument.SelectedSpans.Select(ts => ts.ToSpan()).OrderBy(s => s.Start).ToList();
                var actualHighlights = context.tagSpans.Select(ts => ts.Span.Span).OrderBy(s => s.Start).ToList();

                Assert.Equal(expectedHighlights, actualHighlights);
            }
        }
コード例 #16
0
        protected override Task ProduceTagsAsync(TaggerContext <IClassificationTag> context)
        {
            Debug.Assert(context.SpansToTag.IsSingle());

            var spanToTag = context.SpansToTag.Single();

            var document = spanToTag.Document;

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

            return(SemanticClassificationUtilities.ProduceTagsAsync(
                       context,
                       spanToTag,
                       classificationService,
                       _typeMap
                       ));
        }
コード例 #17
0
        private async Task AddTagSpansAsync(
            TaggerContext <NavigableHighlightTag> context,
            Solution solution,
            DocumentHighlights documentHighlights)
        {
            var cancellationToken = context.CancellationToken;
            var document          = documentHighlights.Document;

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var textSnapshot = text.FindCorrespondingEditorTextSnapshot();

            if (textSnapshot == null)
            {
                // There is no longer an editor snapshot for this document, so we can't care about the
                // results.
                return;
            }

            foreach (var span in documentHighlights.HighlightSpans)
            {
                var tag = GetTag(span);
                context.AddTag(new TagSpan <NavigableHighlightTag>(
                                   textSnapshot.GetSpan(Span.FromBounds(span.TextSpan.Start, span.TextSpan.End)), tag));
            }
        }
コード例 #18
0
        public static async Task ProduceTagsAsync(
            TaggerContext <IClassificationTag> context,
            DocumentSnapshotSpan spanToTag,
            IClassificationService classificationService,
            ClassificationTypeMap typeMap)
        {
            var document = spanToTag.Document;

            if (document == null)
            {
                return;
            }

            var classified = await TryClassifyContainingMemberSpan(
                context, spanToTag, classificationService, typeMap).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, spanToTag, classificationService, typeMap).ConfigureAwait(false);
        }
コード例 #19
0
        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;
            }
        }
コード例 #20
0
        protected override async Task ProduceTagsAsync(
            TaggerContext <IClassificationTag> context,
            DocumentSnapshotSpan snapshotSpan,
            int?caretPosition)
        {
            // Asked to classify when the document is no longer part of a workspace,
            // this can happen when the document/project is being closed.
            if (snapshotSpan.Document == null)
            {
                return;
            }

            // Classify documents in chunks of 50k.   This allows more important work (like
            // completion) to pre-empt classification on our semantic thread.  It also keeps
            // the size of the responses that we need to marshal from the script side smaller.

            var       document  = snapshotSpan.Document;
            var       snapshot  = snapshotSpan.SnapshotSpan.Snapshot;
            var       start     = snapshotSpan.SnapshotSpan.Start.Position;
            var       end       = snapshotSpan.SnapshotSpan.End.Position;
            const int chunkSize = 50 * 1024;

            for (var i = start; i < end; i += chunkSize)
            {
                var subSpan = Span.FromBounds(i, Math.Min(i + chunkSize, end));
                await this.ProduceTagsAsync(
                    context,
                    new DocumentSnapshotSpan(document, new SnapshotSpan(snapshot, subSpan))).ConfigureAwait(false);
            }
        }
コード例 #21
0
 internal async Task ProduceTagsAsync(TaggerContext <BraceHighlightTag> context, Document document, ITextSnapshot snapshot, int position)
 {
     using (Logger.LogBlock(FunctionId.Tagger_BraceHighlighting_TagProducer_ProduceTags, context.CancellationToken))
     {
         await ProduceTagsForBracesAsync(context, document, snapshot, position, rightBrace : false).ConfigureAwait(false);
         await ProduceTagsForBracesAsync(context, document, snapshot, position - 1, rightBrace : true).ConfigureAwait(false);
     }
 }
コード例 #22
0
            private static Task ProduceTagsAsync(TaggerContext <IClassificationTag> context, DocumentSnapshotSpan documentSpan, ClassificationTypeMap typeMap)
            {
                var classificationService = documentSpan.Document.GetLanguageService <IClassificationService>();

                return(classificationService != null
                    ? SemanticClassificationUtilities.ProduceTagsAsync(context, documentSpan, classificationService, typeMap)
                    : Task.CompletedTask);
            }
コード例 #23
0
        protected override async Task ProduceTagsAsync(TaggerContext <IErrorTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition)
        {
            var document = spanToTag.Document;
            var snapshot = spanToTag.SnapshotSpan.Snapshot;

            var diagnostics = await _diagnosticService.GetDiagnosticsAsync(document.Id, context.CancellationToken);

            AddDiagnostics(context, diagnostics, snapshot);
        }
コード例 #24
0
        private static async Task<bool> TryClassifyContainingMemberSpan(TaggerContext<IClassificationTag> context, DocumentSnapshotSpan spanToTag,
            IEditorClassificationService classificationService, ClassificationTypeMap typeMap)
        {
            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
            var document = spanToTag.Document;
            var cancellationToken = context.CancellationToken;

            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.Project.LanguageServices.GetService<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.GetSyntaxRootAsync(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 subSpan = subTextSpan.Contains(changedSpan) ? subTextSpan.ToSpan() : member.FullSpan.ToSpan();

            var subSpanToTag = new DocumentSnapshotSpan(spanToTag.Document,
                new SnapshotSpan(spanToTag.SnapshotSpan.Snapshot, subSpan));

            // re-classify only the member we're inside.
            await ClassifySpansAsync(context, subSpanToTag, classificationService, typeMap).ConfigureAwait(false);
            return true;
        }
コード例 #25
0
        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));
                    }
                }
        }
コード例 #26
0
        protected async Task TestBraceHighlightingAsync(
            string markup,
            ParseOptions options        = null,
            bool swapAnglesWithBrackets = false
            )
        {
            MarkupTestFile.GetPositionAndSpans(
                markup,
                out var text,
                out int cursorPosition,
                out var expectedSpans
                );

            // needed because markup test file can't support [|[|] to indicate selecting
            // just an open bracket.
            if (swapAnglesWithBrackets)
            {
                text = text.Replace("<", "[").Replace(">", "]");
            }

            using (var workspace = CreateWorkspace(text, options))
            {
                WpfTestRunner.RequireWpfFact(
                    $"{nameof(AbstractBraceHighlightingTests)}.{nameof(TestBraceHighlightingAsync)} creates asynchronous taggers"
                    );

                var provider = new BraceHighlightingViewTaggerProvider(
                    workspace.GetService <IThreadingContext>(),
                    GetBraceMatchingService(workspace),
                    workspace.GetService <IForegroundNotificationService>(),
                    AsynchronousOperationListenerProvider.NullProvider
                    );

                var testDocument = workspace.Documents.First();
                var buffer       = testDocument.GetTextBuffer();
                var document     = buffer.CurrentSnapshot
                                   .GetRelatedDocumentsWithChanges()
                                   .FirstOrDefault();
                var context = new TaggerContext <BraceHighlightTag>(
                    document,
                    buffer.CurrentSnapshot,
                    new SnapshotPoint(buffer.CurrentSnapshot, cursorPosition)
                    );
                await provider.GetTestAccessor().ProduceTagsAsync(context);

                var expectedHighlights = expectedSpans
                                         .Select(ts => ts.ToSpan())
                                         .OrderBy(s => s.Start)
                                         .ToList();
                var actualHighlights = context.tagSpans
                                       .Select(ts => ts.Span.Span)
                                       .OrderBy(s => s.Start)
                                       .ToList();

                Assert.Equal(expectedHighlights, actualHighlights);
            }
        }
コード例 #27
0
            public IEnumerable <ITagSpan <IClassificationTag> > GetAllTags(NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken)
            {
                this.AssertIsForeground();
                if (spans.Count == 0)
                {
                    return(Array.Empty <ITagSpan <IClassificationTag> >());
                }

                var firstSpan = spans.First();
                var snapshot  = firstSpan.Snapshot;

                Debug.Assert(snapshot.TextBuffer == _subjectBuffer);

                // We want to classify from the start of the first requested span to the end of the
                // last requested span.
                var spanToTag = new SnapshotSpan(snapshot,
                                                 Span.FromBounds(spans.First().Start, spans.Last().End));

                // We don't need to actually classify if what we're being asked for is a subspan
                // of the last classification we performed.
                var cachedTaggedSpan = this.CachedTaggedSpan;
                var canReuseCache    =
                    cachedTaggedSpan?.Snapshot == snapshot &&
                    cachedTaggedSpan.Value.Contains(spanToTag);

                if (!canReuseCache)
                {
                    // Our cache is not there, or is out of date.  We need to compute the up to date
                    // results.

                    var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
                    if (document == null)
                    {
                        return(Array.Empty <ITagSpan <IClassificationTag> >());
                    }

                    _classificationService = _classificationService ?? document.Project.LanguageServices.GetService <IEditorClassificationService>();

                    var context = new TaggerContext <IClassificationTag>(document, snapshot, cancellationToken: cancellationToken);

                    var task = SemanticClassificationUtilities.ProduceTagsAsync(
                        context, new DocumentSnapshotSpan(document, spanToTag),
                        _classificationService, _owner._typeMap);
                    task.Wait(cancellationToken);

                    CachedTaggedSpan = spanToTag;
                    CachedTags       = new TagSpanIntervalTree <IClassificationTag>(snapshot.TextBuffer, SpanTrackingMode.EdgeExclusive, context.tagSpans);
                }

                if (this.CachedTags == null)
                {
                    return(Array.Empty <ITagSpan <IClassificationTag> >());
                }

                return(this.CachedTags.GetIntersectingTagSpans(spans));
            }
コード例 #28
0
        protected override Task ProduceTagsAsync(TaggerContext<BraceHighlightTag> context, DocumentSnapshotSpan documentSnapshotSpan, int? caretPosition)
        {
            var document = documentSnapshotSpan.Document;
            if (!caretPosition.HasValue || document == null)
            {
                return Task.CompletedTask;
            }

            return ProduceTagsAsync(context, document, documentSnapshotSpan.SnapshotSpan.Snapshot, caretPosition.Value);
        }
コード例 #29
0
        private void ProduceTags(
            TaggerContext <TTag> context, DocumentSnapshotSpan spanToTag,
            Workspace workspace, Document document, SourceText sourceText,
            NormalizedSnapshotSpanCollection suppressedDiagnosticsSpans,
            UpdatedEventArgs updateArgs, CancellationToken cancellationToken)
        {
            try
            {
                var id          = updateArgs.Id;
                var diagnostics = _diagnosticService.GetDiagnostics(
                    workspace, document.Project.Id, document.Id, id, false, cancellationToken);

                var isLiveUpdate = id is ISupportLiveUpdate;

                var requestedSpan  = spanToTag.SnapshotSpan;
                var editorSnapshot = requestedSpan.Snapshot;

                foreach (var diagnosticData in diagnostics)
                {
                    if (this.IncludeDiagnostic(diagnosticData))
                    {
                        // We're going to be retrieving the diagnostics against the last time the engine
                        // computed them against this document *id*.  That might have been a different
                        // version of the document vs what we're looking at now.  But that's ok:
                        //
                        // 1) GetExistingOrCalculatedTextSpan will ensure that the diagnostics spans are
                        //    contained within 'editorSnapshot'.
                        // 2) We'll eventually hear about an update to the diagnostics for this document
                        //    for whatever edits happened between the last time and this current snapshot.
                        //    So we'll eventually reach a point where the diagnostics exactly match the
                        //    editorSnapshot.

                        var diagnosticSpan = diagnosticData.GetExistingOrCalculatedTextSpan(sourceText)
                                             .ToSnapshotSpan(editorSnapshot);

                        if (diagnosticSpan.IntersectsWith(requestedSpan) &&
                            !IsSuppressed(suppressedDiagnosticsSpans, diagnosticSpan))
                        {
                            var tagSpan = this.CreateTagSpan(isLiveUpdate, diagnosticSpan, diagnosticData);
                            if (tagSpan != null)
                            {
                                context.AddTag(tagSpan);
                            }
                        }
                    }
                }
            }
            catch (ArgumentOutOfRangeException ex) when(FatalError.ReportWithoutCrash(ex))
            {
                // https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=428328&_a=edit&triage=false
                // explicitly report NFW to find out what is causing us for out of range.
                // stop crashing on such occations
                return;
            }
        }
コード例 #30
0
 private void AddBraces(
     TaggerContext <BraceHighlightTag> context,
     ITextSnapshot snapshot,
     BraceMatchingResult?braces)
 {
     if (braces.HasValue)
     {
         context.AddTag(snapshot.GetTagSpan(braces.Value.LeftSpan.ToSpan(), BraceHighlightTag.StartTag));
         context.AddTag(snapshot.GetTagSpan(braces.Value.RightSpan.ToSpan(), BraceHighlightTag.EndTag));
     }
 }
コード例 #31
0
        protected override Task ProduceTagsAsync(TaggerContext <IClassificationTag> context)
        {
            Debug.Assert(context.SpansToTag.IsSingle());

            var spanToTag = context.SpansToTag.Single();

            var task1 = ProduceTagsAsync(context, spanToTag, WorkspaceClassificationDelegationService.Instance);
            var task2 = ProduceTagsAsync(context, spanToTag, EditorClassificationDelegationService.Instance);

            return(Task.WhenAll(task1, task2));
        }
コード例 #32
0
        protected override Task ProduceTagsAsync(TaggerContext <BraceHighlightTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition)
        {
            var document = spanToTag.Document;

            if (!caretPosition.HasValue || document == null)
            {
                return(SpecializedTasks.EmptyTask);
            }

            return(ProduceTagsAsync(context, document, spanToTag.SnapshotSpan.Snapshot, caretPosition.Value));
        }
コード例 #33
0
        public static async Task ProduceTagsAsync(TaggerContext<IClassificationTag> context, DocumentSnapshotSpan spanToTag,
            IEditorClassificationService classificationService, ClassificationTypeMap typeMap)
        {
            var document = spanToTag.Document;
            if (document == null)
            {
                return;
            }

            if (await TryClassifyContainingMemberSpan(context, spanToTag, classificationService, typeMap).ConfigureAwait(false))
            {
                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, spanToTag, classificationService, typeMap).ConfigureAwait(false);
        }
コード例 #34
0
        private static async Task<List<IOutliningRegionTag>> GetTagsFromWorkspaceAsync(TestWorkspace workspace)
        {
            var hostdoc = workspace.Documents.First();
            var view = hostdoc.GetTextView();
            var textService = workspace.GetService<ITextEditorFactoryService>();
            var editorService = workspace.GetService<IEditorOptionsFactoryService>();
            var projectionService = workspace.GetService<IProjectionBufferFactoryService>();

            var provider = new OutliningTaggerProvider(
                workspace.ExportProvider.GetExportedValue<IForegroundNotificationService>(),
                textService, editorService, projectionService,
                AggregateAsynchronousOperationListener.EmptyListeners);

            var document = workspace.CurrentSolution.GetDocument(hostdoc.Id);
            var context = new TaggerContext<IOutliningRegionTag>(document, view.TextSnapshot);
            await provider.ProduceTagsAsync_ForTestingPurposesOnly(context);

            return context.tagSpans.Select(x => x.Tag).ToList();
        }
コード例 #35
0
        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;
            }
        }