-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cohost document highlighting (#10656)
Part of #9519 Brings document highlight to cohosting, including tests. Also added some basic tests for `RazorServices` and `Services.props`.
- Loading branch information
Showing
18 changed files
with
629 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
...osoft.CodeAnalysis.Razor.Workspaces/Protocol/DocumentHighlight/RemoteDocumentHighlight.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Runtime.Serialization; | ||
using Microsoft.CodeAnalysis.Razor.Workspaces; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Microsoft.VisualStudio.LanguageServer.Protocol; | ||
using RLSP = Roslyn.LanguageServer.Protocol; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight; | ||
|
||
using DocumentHighlight = VisualStudio.LanguageServer.Protocol.DocumentHighlight; | ||
|
||
[DataContract] | ||
internal readonly record struct RemoteDocumentHighlight( | ||
[property: DataMember(Order = 0)] LinePositionSpan Position, | ||
[property: DataMember(Order = 1)] DocumentHighlightKind Kind) | ||
{ | ||
public static RemoteDocumentHighlight FromRLSPDocumentHighlight(RLSP.DocumentHighlight h) | ||
=> new RemoteDocumentHighlight(h.Range.ToLinePositionSpan(), (DocumentHighlightKind)h.Kind); | ||
|
||
public static DocumentHighlight ToLspDocumentHighlight(RemoteDocumentHighlight r) | ||
=> new DocumentHighlight | ||
{ | ||
Range = r.Position.ToRange(), | ||
Kind = r.Kind | ||
}; | ||
} |
15 changes: 15 additions & 0 deletions
15
...zor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteDocumentHighlightService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
using Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Remote; | ||
|
||
internal interface IRemoteDocumentHighlightService | ||
{ | ||
ValueTask<RemoteResponse<RemoteDocumentHighlight[]?>> GetHighlightsAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId documentId, LinePosition position, CancellationToken cancellationToken); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 29 additions & 15 deletions
44
src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,51 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.AspNetCore.Razor.Serialization.MessagePack.Resolvers; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Remote; | ||
|
||
internal static class RazorServices | ||
{ | ||
private const string ComponentName = "Razor"; | ||
|
||
public static readonly RazorServiceDescriptorsWrapper Descriptors = new( | ||
ComponentName, | ||
featureDisplayNameProvider: feature => $"Razor {feature} Feature", | ||
additionalFormatters: [], | ||
additionalResolvers: TopLevelResolvers.All, | ||
interfaces: | ||
// Internal for testing | ||
internal static readonly IEnumerable<(Type, Type?)> MessagePackServices = | ||
[ | ||
(typeof(IRemoteLinkedEditingRangeService), null), | ||
(typeof(IRemoteTagHelperProviderService), null), | ||
(typeof(IRemoteClientInitializationService), null), | ||
(typeof(IRemoteSemanticTokensService), null), | ||
(typeof(IRemoteHtmlDocumentService), null), | ||
(typeof(IRemoteUriPresentationService), null), | ||
(typeof(IRemoteFoldingRangeService), null) | ||
]); | ||
(typeof(IRemoteFoldingRangeService), null), | ||
(typeof(IRemoteDocumentHighlightService), null), | ||
]; | ||
|
||
// Internal for testing | ||
internal static readonly IEnumerable<(Type, Type?)> JsonServices = | ||
[ | ||
(typeof(IRemoteSignatureHelpService), null), | ||
]; | ||
|
||
private const string ComponentName = "Razor"; | ||
|
||
public static readonly RazorServiceDescriptorsWrapper Descriptors = new( | ||
ComponentName, | ||
featureDisplayNameProvider: GetFeatureDisplayName, | ||
additionalFormatters: [], | ||
additionalResolvers: TopLevelResolvers.All, | ||
interfaces: MessagePackServices); | ||
|
||
public static readonly RazorServiceDescriptorsWrapper JsonDescriptors = new( | ||
ComponentName, // Needs to match the above because so much of our ServiceHub infrastructure is convention based | ||
featureDisplayNameProvider: feature => $"Razor {feature} Feature", | ||
featureDisplayNameProvider: GetFeatureDisplayName, | ||
jsonConverters: RazorServiceDescriptorsWrapper.GetLspConverters(), | ||
interfaces: | ||
[ | ||
(typeof(IRemoteSignatureHelpService), null), | ||
]); | ||
interfaces: JsonServices); | ||
|
||
private static string GetFeatureDisplayName(string feature) | ||
{ | ||
return $"Razor {feature} Feature"; | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RemoteResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Runtime.Serialization; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Remote; | ||
|
||
[DataContract] | ||
internal record struct RemoteResponse<T>( | ||
[property: DataMember(Order = 0)] bool StopHandling, | ||
[property: DataMember(Order = 1)] T Result) | ||
{ | ||
public static RemoteResponse<T> CallHtml => new(StopHandling: false, Result: default!); | ||
public static RemoteResponse<T> NoFurtherHandling => new(StopHandling: true, Result: default!); | ||
public static RemoteResponse<T> Results(T result) => new(StopHandling: false, Result: result); | ||
} |
92 changes: 92 additions & 0 deletions
92
...c/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Razor.Language; | ||
using Microsoft.AspNetCore.Razor.PooledObjects; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; | ||
using Microsoft.CodeAnalysis.Razor.DocumentMapping; | ||
using Microsoft.CodeAnalysis.Razor.Protocol; | ||
using Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight; | ||
using Microsoft.CodeAnalysis.Razor.Remote; | ||
using Microsoft.CodeAnalysis.Razor.Workspaces; | ||
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight.RemoteDocumentHighlight[]?>; | ||
|
||
namespace Microsoft.CodeAnalysis.Remote.Razor; | ||
|
||
internal sealed partial class RemoteDocumentHighlightService(in ServiceArgs args) : RazorDocumentServiceBase(in args), IRemoteDocumentHighlightService | ||
{ | ||
internal sealed class Factory : FactoryBase<IRemoteDocumentHighlightService> | ||
{ | ||
protected override IRemoteDocumentHighlightService CreateService(in ServiceArgs args) | ||
=> new RemoteDocumentHighlightService(in args); | ||
} | ||
|
||
private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue<IRazorDocumentMappingService>(); | ||
private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue<IFilePathService>(); | ||
|
||
public ValueTask<Response> GetHighlightsAsync( | ||
RazorPinnedSolutionInfoWrapper solutionInfo, | ||
DocumentId razorDocumentId, | ||
LinePosition position, | ||
CancellationToken cancellationToken) | ||
=> RunServiceAsync( | ||
solutionInfo, | ||
razorDocumentId, | ||
context => GetHighlightsAsync(context, position, cancellationToken), | ||
cancellationToken); | ||
|
||
private async ValueTask<Response> GetHighlightsAsync( | ||
RemoteDocumentContext context, | ||
LinePosition position, | ||
CancellationToken cancellationToken) | ||
{ | ||
var sourceText = await context.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); | ||
if (!sourceText.TryGetAbsoluteIndex(position.Line, position.Character, out var index)) | ||
{ | ||
return Response.NoFurtherHandling; | ||
} | ||
|
||
var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); | ||
|
||
var languageKind = _documentMappingService.GetLanguageKind(codeDocument, index, rightAssociative: true); | ||
if (languageKind is RazorLanguageKind.Html) | ||
{ | ||
return Response.CallHtml; | ||
} | ||
else if (languageKind is RazorLanguageKind.Razor) | ||
{ | ||
return Response.NoFurtherHandling; | ||
} | ||
|
||
var csharpDocument = codeDocument.GetCSharpDocument(); | ||
if (_documentMappingService.TryMapToGeneratedDocumentPosition(csharpDocument, index, out var mappedPosition, out _)) | ||
{ | ||
var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false); | ||
|
||
var highlights = await DocumentHighlights.GetHighlightsAsync(generatedDocument, mappedPosition, cancellationToken).ConfigureAwait(false); | ||
|
||
if (highlights is not null) | ||
{ | ||
using var results = new PooledArrayBuilder<RemoteDocumentHighlight>(); | ||
|
||
foreach (var highlight in highlights) | ||
{ | ||
if (_documentMappingService.TryMapToHostDocumentRange(csharpDocument, highlight.Range.ToLinePositionSpan(), out var mappedRange)) | ||
{ | ||
highlight.Range = mappedRange.ToRLSPRange(); | ||
results.Add(RemoteDocumentHighlight.FromRLSPDocumentHighlight(highlight)); | ||
} | ||
} | ||
|
||
return Response.Results(results.ToArray()); | ||
} | ||
} | ||
|
||
return Response.NoFurtherHandling; | ||
} | ||
} |
Oops, something went wrong.