private static async Task <ImmutableArray <DocumentHighlight> > GetReferenceHighlightsAsync(Document document, SourceText text, int position, CancellationToken cancellationToken) { var documentHighlightService = document.GetRequiredLanguageService <IDocumentHighlightsService>(); var options = DocumentHighlightingOptions.From(document.Project); var highlights = await documentHighlightService.GetDocumentHighlightsAsync( document, position, ImmutableHashSet.Create(document), options, cancellationToken).ConfigureAwait(false); if (!highlights.IsDefaultOrEmpty) { // LSP requests are only for a single document. So just get the highlights for the requested document. var highlightsForDocument = highlights.FirstOrDefault(h => h.Document.Id == document.Id); return(highlightsForDocument.HighlightSpans.SelectAsArray(h => new DocumentHighlight { Range = ProtocolConversions.TextSpanToRange(h.TextSpan, text), Kind = ProtocolConversions.HighlightSpanKindToDocumentHighlightKind(h.Kind), })); } return(ImmutableArray <DocumentHighlight> .Empty); }
private static async Task ProduceTagsAsync( TaggerContext <NavigableHighlightTag> context, SnapshotPoint position, Document document, DocumentHighlightingOptions options, CancellationToken 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, options, cancellationToken).ConfigureAwait(false); if (documentHighlightsList != null) { foreach (var documentHighlights in documentHighlightsList) { AddTagSpans(context, documentHighlights, cancellationToken); } } } } } }
protected override Task ProduceTagsAsync( TaggerContext <NavigableHighlightTag> context, CancellationToken cancellationToken) { // NOTE(cyrusn): Normally we'd limit ourselves to producing tags in the span we were // asked about. However, we want to produce all tags here so that the user can actually // navigate between all of them using the appropriate tag navigation commands. If we // don't generate all the tags then the user will cycle through an incorrect subset. if (context.CaretPosition == null) { return(Task.CompletedTask); } var caretPosition = context.CaretPosition.Value; // GetSpansToTag may have produced no actual spans to tag. Be resilient to that. var document = context.SpansToTag.FirstOrDefault(vt => vt.SnapshotSpan.Snapshot == caretPosition.Snapshot).Document; if (document == null) { return(Task.CompletedTask); } // Don't produce tags if the feature is not enabled. if (!_globalOptions.GetOption(FeatureOnOffOptions.ReferenceHighlighting, document.Project.Language)) { return(Task.CompletedTask); } // 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(caretPosition); if (!existingTags.IsEmpty()) { context.SetSpansTagged(SpecializedCollections.EmptyEnumerable <DocumentSnapshotSpan>()); return(Task.CompletedTask); } // Otherwise, we need to go produce all tags. var options = DocumentHighlightingOptions.From(document.Project); return(ProduceTagsAsync(context, caretPosition, document, options, cancellationToken)); }
public override async Task <DocumentHighlight[]?> HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; if (document == null) { return(null); } var documentHighlightService = document.Project.LanguageServices.GetRequiredService <IDocumentHighlightsService>(); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); var options = DocumentHighlightingOptions.From(document.Project); var highlights = await documentHighlightService.GetDocumentHighlightsAsync( document, position, ImmutableHashSet.Create(document), options, cancellationToken).ConfigureAwait(false); if (!highlights.IsDefaultOrEmpty) { // LSP requests are only for a single document. So just get the highlights for the requested document. var highlightsForDocument = highlights.FirstOrDefault(h => h.Document.Id == document.Id); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return(highlightsForDocument.HighlightSpans.Select(h => new DocumentHighlight { Range = ProtocolConversions.TextSpanToRange(h.TextSpan, text), Kind = ProtocolConversions.HighlightSpanKindToDocumentHighlightKind(h.Kind), }).ToArray()); } return(Array.Empty <DocumentHighlight>()); }
public async Task <ImmutableArray <DocumentHighlights> > GetDocumentHighlightsAsync(Document document, int position, IImmutableSet <Document> documentsToSearch, DocumentHighlightingOptions options, CancellationToken cancellationToken) { var highlights = await _service.GetDocumentHighlightsAsync(document, position, documentsToSearch, cancellationToken).ConfigureAwait(false); return(highlights.SelectAsArray(x => new DocumentHighlights(x.Document, MapHighlightSpans(x.HighlightSpans)))); }
Task <ImmutableArray <DocumentHighlights> > IDocumentHighlightsService.GetDocumentHighlightsAsync( Document document, int position, IImmutableSet <Document> documentsToSearch, DocumentHighlightingOptions options, CancellationToken cancellationToken) => GetDocumentHighlightsAsync(document, position, documentsToSearch, cancellationToken);