diff --git a/src/EditorFeatures/Core/EditorFeatures.csproj b/src/EditorFeatures/Core/EditorFeatures.csproj
index 000857eca1df7d24f2704ee30a685387d1cfadc1..9edc6adfec5091953852f006b4a6a11ed3a7c6eb 100644
--- a/src/EditorFeatures/Core/EditorFeatures.csproj
+++ b/src/EditorFeatures/Core/EditorFeatures.csproj
@@ -165,6 +165,7 @@
+
diff --git a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c36aaed9954cd77c0a28ea5c7d01da5222f154ba
--- /dev/null
+++ b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.Editor
+{
+ internal enum HighlightSpanKind
+ {
+ None,
+ Definition,
+ Reference,
+ WrittenReference,
+ }
+
+ internal struct HighlightSpan
+ {
+ public TextSpan TextSpan { get; }
+ public HighlightSpanKind Kind { get; }
+
+ public HighlightSpan(TextSpan textSpan, HighlightSpanKind kind) : this()
+ {
+ this.TextSpan = textSpan;
+ this.Kind = kind;
+ }
+ }
+
+ internal struct DocumentHighlights
+ {
+ public Document Document { get; }
+ public ImmutableArray HighlightSpans { get; }
+
+ public DocumentHighlights(Document document, ImmutableArray highlightSpans)
+ {
+ this.Document = document;
+ this.HighlightSpans = highlightSpans;
+ }
+ }
+
+ ///
+ /// Note: kept around for back compat until F# and TypeScript move over to
+ /// .
+ ///
+ internal interface IDocumentHighlightsService : ILanguageService
+ {
+ Task> GetDocumentHighlightsAsync(
+ Document document, int position, IImmutableSet documentsToSearch, CancellationToken cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
index e2367ad5f5d3de2b313a1046520578c9566c928d..94ab3331cb6680944eee3fb902d8fc5f34e7dd42 100644
--- a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
+++ b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
@@ -5,14 +5,17 @@
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.DocumentHighlighting;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.Editor.Shared.Tagging;
using Microsoft.CodeAnalysis.Editor.Tagging;
+using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Options;
+using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
@@ -111,13 +114,12 @@ protected override Task ProduceTagsAsync(TaggerContext co
}
// Otherwise, we need to go produce all tags.
- return ProduceTagsAsync(context, caretPosition, workspace, document);
+ return ProduceTagsAsync(context, caretPosition, document);
}
internal async Task ProduceTagsAsync(
TaggerContext context,
SnapshotPoint position,
- Workspace workspace,
Document document)
{
var cancellationToken = context.CancellationToken;
@@ -128,25 +130,73 @@ protected override Task ProduceTagsAsync(TaggerContext co
{
if (document != null)
{
- var documentHighlightsService = document.Project.LanguageServices.GetService();
- if (documentHighlightsService != null)
+ // As we transition to the new API (defined at the Features layer) we support
+ // calling into both it and the old API (defined at the EditorFeatures layer).
+ //
+ // Once TypeScript and F# can move over, then we can remove the calls to the old
+ // API.
+ await TryNewServiceAsync(context, position, document).ConfigureAwait(false);
+ await TryOldServiceAsync(context, position, document).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private Task TryOldServiceAsync(TaggerContext context, SnapshotPoint position, Document document)
+ {
+ return TryServiceAsync(
+ context, position, document,
+ (s, d, p, ds, c) => s.GetDocumentHighlightsAsync(d, p, ds, c));
+ }
+
+ private Task TryNewServiceAsync(
+ TaggerContext context, SnapshotPoint position, Document document)
+ {
+ return TryServiceAsync(
+ context, position, document,
+ async (service, doc, point, documents, cancellation) =>
+ {
+ // Call into the new service.
+ var newHighlights = await service.GetDocumentHighlightsAsync(doc, point, documents, cancellation).ConfigureAwait(false);
+
+ // then convert the result to the form the old service would return.
+ return ConvertHighlights(newHighlights);
+ });
+ }
+
+ private async Task TryServiceAsync(
+ TaggerContext context, SnapshotPoint position, Document document,
+ Func, CancellationToken, Task>> getDocumentHighlightsAsync)
+ where T : class, ILanguageService
+ {
+ var cancellationToken = context.CancellationToken;
+ var documentHighlightsService = document.GetLanguageService();
+ if (documentHighlightsService != 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 getDocumentHighlightsAsync(
+ documentHighlightsService, document, position, documentsToSearch, cancellationToken).ConfigureAwait(false);
+ if (documentHighlightsList != null)
+ {
+ foreach (var documentHighlights in documentHighlightsList)
{
- // 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 documentHighlightsService.GetDocumentHighlightsAsync(document, position, documentsToSearch, cancellationToken).ConfigureAwait(false);
- if (documentHighlightsList != null)
- {
- foreach (var documentHighlights in documentHighlightsList)
- {
- await AddTagSpansAsync(context, solution, documentHighlights).ConfigureAwait(false);
- }
- }
+ await AddTagSpansAsync(
+ context, document.Project.Solution, documentHighlights).ConfigureAwait(false);
}
}
}
}
+ private ImmutableArray ConvertHighlights(ImmutableArray newHighlights)
+ => newHighlights.SelectAsArray(
+ documentHighlights => new DocumentHighlights(
+ documentHighlights.Document,
+ documentHighlights.HighlightSpans.SelectAsArray(
+ highlightSpan => new HighlightSpan(
+ highlightSpan.TextSpan,
+ (HighlightSpanKind)highlightSpan.Kind))));
+
private async Task AddTagSpansAsync(
TaggerContext context,
Solution solution,