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