diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs index 8f8a680ae8f..efeead6a96e 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs @@ -49,7 +49,7 @@ public enum FileTypes public async Task SetupAsync() { CodeActionEndpoint = new CodeActionEndpoint( - documentMappingService: RazorLanguageServerHost.GetRequiredService(), + documentMappingService: RazorLanguageServerHost.GetRequiredService(), razorCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), csharpCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), htmlCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs index f9baad11704..0bf6c9fea83 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs @@ -38,7 +38,7 @@ public async Task SetupAsync() var razorCompletionListProvider = RazorLanguageServerHost.GetRequiredService(); var lspServices = RazorLanguageServerHost.GetRequiredService(); var responseRewriters = lspServices.GetRequiredServices(); - var documentMappingService = lspServices.GetRequiredService(); + var documentMappingService = lspServices.GetRequiredService(); var clientConnection = lspServices.GetRequiredService(); var completionListCache = lspServices.GetRequiredService(); var loggerFactory = lspServices.GetRequiredService(); @@ -141,7 +141,7 @@ public async Task RazorCompletionAsync() private class TestDelegatedCompletionListProvider : DelegatedCompletionListProvider { - public TestDelegatedCompletionListProvider(IEnumerable responseRewriters, IRazorDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) + public TestDelegatedCompletionListProvider(IEnumerable responseRewriters, IDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) : base(responseRewriters, documentMappingService, clientConnection, completionListCache) { } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs index 7cb21677aa5..9e50156d7f5 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs @@ -115,9 +115,9 @@ private protected override LanguageServerFeatureOptions BuildFeatureOptions() MockBehavior.Strict); } - private IRazorDocumentMappingService BuildRazorDocumentMappingService() + private IDocumentMappingService BuildRazorDocumentMappingService() { - var razorDocumentMappingService = new Mock(MockBehavior.Strict); + var razorDocumentMappingService = new Mock(MockBehavior.Strict); Range? hostDocumentRange; razorDocumentMappingService.Setup( diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs index d489b9ec124..c3371b04891 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs @@ -19,7 +19,7 @@ public class RazorDocumentMappingBenchmark : RazorLanguageServerBenchmarkBase { private string _filePath; - private IRazorDocumentMappingService DocumentMappingService { get; set; } + private IDocumentMappingService DocumentMappingService { get; set; } private IDocumentSnapshot DocumentSnapshot { get; set; } @@ -171,6 +171,6 @@ public async Task CleanupServerAsync() private void EnsureServicesInitialized() { - DocumentMappingService = RazorLanguageServerHost.GetRequiredService(); + DocumentMappingService = RazorLanguageServerHost.GetRequiredService(); } } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs index 6f053edeadc..d7825241214 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs @@ -108,7 +108,7 @@ internal class TestRazorSemanticTokensInfoService : RazorSemanticTokensInfoServi { public TestRazorSemanticTokensInfoService( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorSemanticTokensLegendService razorSemanticTokensLegendService, ILoggerFactory loggerFactory) : base(documentMappingService, razorSemanticTokensLegendService, csharpSemanticTokensProvider: null!, languageServerFeatureOptions, loggerFactory) diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs index 6bd676543de..8258f197fc8 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs @@ -140,7 +140,7 @@ internal class TestCustomizableRazorSemanticTokensInfoService : RazorSemanticTok { public TestCustomizableRazorSemanticTokensInfoService( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorSemanticTokensLegendService razorSemanticTokensLegendService, ILoggerFactory loggerFactory) : base(documentMappingService, razorSemanticTokensLegendService, csharpSemanticTokensProvider: null!, languageServerFeatureOptions, loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs index 88574c846ba..dfef778fe71 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs @@ -22,13 +22,13 @@ internal abstract class AbstractRazorDelegatingEndpoint : I where TRequest : ITextDocumentPositionParams { private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; protected readonly ILogger Logger; protected AbstractRazorDelegatingEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILogger logger) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs index ea7d46e8e45..30565f8c181 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert; [RazorLanguageServerEndpoint(VSInternalMethods.OnAutoInsertName)] internal class OnAutoInsertEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IEnumerable onAutoInsertProvider, RazorLSPOptionsMonitor optionsMonitor, @@ -170,7 +170,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedOnAutoInsertParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), positionInfo.Position, positionInfo.LanguageKind, request.Character, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs index 3169a1d7648..8df88d48145 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs @@ -20,7 +20,7 @@ internal class PreferHtmlInAttributeValuesDocumentPositionInfoStrategy : IDocume { public static IDocumentPositionInfoStrategy Instance { get; } = new PreferHtmlInAttributeValuesDocumentPositionInfoStrategy(); - public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) + public async Task TryGetPositionInfoAsync(IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) { var defaultDocumentPositionInfo = await DefaultDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(documentMappingService, documentContext, position, cancellationToken).ConfigureAwait(false); if (defaultDocumentPositionInfo is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs index df9aaf7fe45..964f576f653 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs @@ -23,10 +23,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; internal sealed class UnformattedRemappingCSharpCodeActionResolver( IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService) : CSharpCodeActionResolver(clientConnection) + IDocumentMappingService documentMappingService) : CSharpCodeActionResolver(clientConnection) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public override string Action => LanguageServerConstants.CodeActions.UnformattedRemap; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 124f3fc5935..4a72ea63208 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; [RazorLanguageServerEndpoint(LspEndpointName)] internal sealed class CodeActionEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IEnumerable razorCodeActionProviders, IEnumerable csharpCodeActionProviders, IEnumerable htmlCodeActionProviders, @@ -42,7 +42,7 @@ internal sealed class CodeActionEndpoint( { private const string LspEndpointName = Methods.TextDocumentCodeActionName; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IEnumerable _razorCodeActionProviders = razorCodeActionProviders ?? throw new ArgumentNullException(nameof(razorCodeActionProviders)); private readonly IEnumerable _csharpCodeActionProviders = csharpCodeActionProviders ?? throw new ArgumentNullException(nameof(csharpCodeActionProviders)); private readonly IEnumerable _htmlCodeActionProviders = htmlCodeActionProviders ?? throw new ArgumentNullException(nameof(htmlCodeActionProviders)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs index 5f7f6d007e0..87ecec1b541 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -14,9 +13,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; -internal sealed class DefaultHtmlCodeActionProvider(IRazorDocumentMappingService documentMappingService) : IHtmlCodeActionProvider +internal sealed class DefaultHtmlCodeActionProvider(IEditMappingService editMappingService) : IHtmlCodeActionProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public async Task> ProvideAsync( RazorCodeActionContext context, @@ -28,7 +27,7 @@ public async Task> ProvideAsync( { if (codeAction.Edit is not null) { - await RemapAndFixHtmlCodeActionEditAsync(_documentMappingService, context.CodeDocument, codeAction, cancellationToken).ConfigureAwait(false); + await RemapAndFixHtmlCodeActionEditAsync(_editMappingService, context.CodeDocument, codeAction, cancellationToken).ConfigureAwait(false); results.Add(codeAction); } @@ -41,11 +40,11 @@ public async Task> ProvideAsync( return results.ToImmutable(); } - public static async Task RemapAndFixHtmlCodeActionEditAsync(IRazorDocumentMappingService documentMappingService, RazorCodeDocument codeDocument, CodeAction codeAction, CancellationToken cancellationToken) + public static async Task RemapAndFixHtmlCodeActionEditAsync(IEditMappingService editMappingService, RazorCodeDocument codeDocument, CodeAction codeAction, CancellationToken cancellationToken) { Assumes.NotNull(codeAction.Edit); - codeAction.Edit = await documentMappingService.RemapWorkspaceEditAsync(codeAction.Edit, cancellationToken).ConfigureAwait(false); + codeAction.Edit = await editMappingService.RemapWorkspaceEditAsync(codeAction.Edit, cancellationToken).ConfigureAwait(false); if (codeAction.Edit.TryGetDocumentChanges(out var documentEdits) == true) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs index 604f02a3458..0fce29fdc6f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs @@ -16,10 +16,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; internal sealed class DefaultHtmlCodeActionResolver( IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService) : HtmlCodeActionResolver(clientConnection) + IEditMappingService editMappingService) : HtmlCodeActionResolver(clientConnection) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public override string Action => LanguageServerConstants.CodeActions.Default; @@ -41,7 +41,7 @@ public async override Task ResolveAsync( } var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - await DefaultHtmlCodeActionProvider.RemapAndFixHtmlCodeActionEditAsync(_documentMappingService, codeDocument, resolvedCodeAction, cancellationToken).ConfigureAwait(false); + await DefaultHtmlCodeActionProvider.RemapAndFixHtmlCodeActionEditAsync(_editMappingService, codeDocument, resolvedCodeAction, cancellationToken).ConfigureAwait(false); return resolvedCodeAction; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs index f79fe80a516..86af5075d71 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs @@ -29,13 +29,13 @@ internal sealed class GenerateMethodCodeActionResolver( IDocumentContextFactory documentContextFactory, RazorLSPOptionsMonitor razorLSPOptionsMonitor, IClientConnection clientConnection, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IRazorFormattingService razorFormattingService) : IRazorCodeActionResolver { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; private readonly RazorLSPOptionsMonitor _razorLSPOptionsMonitor = razorLSPOptionsMonitor; private readonly IClientConnection _clientConnection = clientConnection; - private readonly IRazorDocumentMappingService _documentMappingService = razorDocumentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IRazorFormattingService _razorFormattingService = razorFormattingService; private const string ReturnType = "$$ReturnType$$"; @@ -166,7 +166,7 @@ private async Task GenerateMethodInCodeBlockAsync( character: 0, editToSendToRoslyn.NewText); - var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, tempTextEdit); + var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.GetTextDocumentIdentifierAndVersion(), RequiresVirtualDocument: true, tempTextEdit); var result = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSimplifyMethodEndpointName, delegatedParams, @@ -194,7 +194,7 @@ private async Task GenerateMethodInCodeBlockAsync( var remappedEdit = VsLspFactory.CreateTextEdit(remappedRange, unformattedMethodSignature); - var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, remappedEdit); + var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.GetTextDocumentIdentifierAndVersion(), RequiresVirtualDocument: true, remappedEdit); var result = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSimplifyMethodEndpointName, delegatedParams, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs index 7d58f7bfbd6..f977eb4b4ff 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs @@ -105,7 +105,13 @@ private async Task PostProcessCompletionItemAsync( return resolvedCompletionItem; } - var formattingOptions = await _clientConnection.SendRequestAsync(CodeAnalysis.Razor.Protocol.LanguageServerConstants.RazorGetFormattingOptionsEndpointName, documentContext.Identifier, cancellationToken).ConfigureAwait(false); + var formattingOptions = await _clientConnection + .SendRequestAsync( + LanguageServerConstants.RazorGetFormattingOptionsEndpointName, + documentContext.GetTextDocumentIdentifierAndVersion(), + cancellationToken) + .ConfigureAwait(false); + if (formattingOptions is null) { return resolvedCompletionItem; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs index e830fee0ff0..2c8e023b46d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs @@ -28,13 +28,13 @@ internal class DelegatedCompletionListProvider .Union(s_razorTriggerCharacters); private readonly ImmutableArray _responseRewriters; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; private readonly CompletionListCache _completionListCache; public DelegatedCompletionListProvider( IEnumerable responseRewriters, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) { @@ -77,7 +77,7 @@ public DelegatedCompletionListProvider( var shouldIncludeSnippets = await ShouldIncludeSnippetsAsync(documentContext, absoluteIndex, cancellationToken).ConfigureAwait(false); var delegatedParams = new DelegatedCompletionParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), positionInfo.Position, positionInfo.LanguageKind, completionContext, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs index f28856851d3..1bcb7c82ec0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs @@ -21,13 +21,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorBreakpointSpanEndpoint)] internal class RazorBreakpointSpanEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly ILogger _logger; public bool MutatesSolutionState => false; public RazorBreakpointSpanEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { if (loggerFactory is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs index cf6700e9a68..844da19f1a8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs @@ -22,11 +22,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorProximityExpressionsEndpoint)] internal class RazorProximityExpressionsEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly ILogger _logger; public RazorProximityExpressionsEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { if (documentMappingService is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs index 5f5c32bb01d..fb811f96c82 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentValidateBreakableRangeName)] internal class ValidateBreakpointRangeEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) @@ -27,7 +27,7 @@ internal class ValidateBreakpointRangeEndpoint( clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; protected override bool OnlySingleServer => false; @@ -67,7 +67,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return new DelegatedValidateBreakpointRangeParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), projectedRange, positionInfo.LanguageKind); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs index a9ebe134264..976829713ad 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs @@ -15,7 +15,7 @@ internal class DefaultDocumentPositionInfoStrategy : IDocumentPositionInfoStrate public static IDocumentPositionInfoStrategy Instance { get; } = new DefaultDocumentPositionInfoStrategy(); public async Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index df34aebc583..304c7729526 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -30,14 +30,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition; [RazorLanguageServerEndpoint(Methods.TextDocumentDefinitionName)] internal sealed class DefinitionEndpoint( IRazorComponentSearchEngine componentSearchEngine, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; protected override bool PreferCSharpOverHtmlIfPossible => true; @@ -112,9 +112,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected async override Task HandleDelegatedResponseAsync(DefinitionResult? response, TextDocumentPositionParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) @@ -267,7 +267,7 @@ private async Task GetNavigateRangeAsync(IDocumentSnapshot documentSnapsh return VsLspFactory.DefaultRange; } - internal static async Task TryGetPropertyRangeAsync(RazorCodeDocument codeDocument, string propertyName, IRazorDocumentMappingService documentMappingService, ILogger logger, CancellationToken cancellationToken) + internal static async Task TryGetPropertyRangeAsync(RazorCodeDocument codeDocument, string propertyName, IDocumentMappingService documentMappingService, ILogger logger, CancellationToken cancellationToken) { // Parse the C# file and find the property that matches the name. // We don't worry about parameter attributes here for two main reasons: diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs index b4277742608..68d893f9b24 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs @@ -147,7 +147,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno private async Task<(VSInternalDiagnosticReport[]? CSharpDiagnostics, VSInternalDiagnosticReport[]? HtmlDiagnostics)> GetHtmlCSharpDiagnosticsAsync(VersionedDocumentContext documentContext, Guid correlationId, CancellationToken cancellationToken) { - var delegatedParams = new DelegatedDiagnosticParams(documentContext.Identifier, correlationId); + var delegatedParams = new DelegatedDiagnosticParams(documentContext.GetTextDocumentIdentifierAndVersion(), correlationId); var delegatedResponse = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorPullDiagnosticEndpointName, delegatedParams, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs index 7831e806f0b..343c772cdec 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; /// Contains several methods for mapping and filtering Razor and C# diagnostics. It allows for /// translating code diagnostics from one representation into another, such as from C# to Razor. /// -/// The . +/// The . /// The . /// -internal class RazorTranslateDiagnosticsService(IRazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) +internal class RazorTranslateDiagnosticsService(IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; // Internal for testing internal static readonly IReadOnlyCollection CSharpDiagnosticsToIgnore = new HashSet() diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs index 5854d01677e..65537539ec2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs @@ -19,11 +19,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentHighlighting; [RazorLanguageServerEndpoint(Methods.TextDocumentDocumentHighlightName)] internal class DocumentHighlightEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public DocumentHighlightEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : base(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()) @@ -56,9 +56,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override async Task HandleDelegatedResponseAsync(DocumentHighlight[]? response, DocumentHighlightParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs index e2134c10ed2..b61b08aa239 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs @@ -25,18 +25,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal abstract class AbstractTextDocumentPresentationEndpointBase : IRazorRequestHandler, ICapabilitiesProvider where TParams : IPresentationParams { - private readonly IRazorDocumentMappingService _razorDocumentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; private readonly IFilePathService _filePathService; private readonly ILogger _logger; protected AbstractTextDocumentPresentationEndpointBase( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, ILogger logger) { - _razorDocumentMappingService = razorDocumentMappingService; + _documentMappingService = documentMappingService; _clientConnection = clientConnection; _filePathService = filePathService; _logger = logger; @@ -79,7 +79,7 @@ protected AbstractTextDocumentPresentationEndpointBase( return null; } - var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); + var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); // See if we can handle this directly in Razor. If not, we'll let things flow to the below delegated handling. var result = await TryGetRazorWorkspaceEditAsync(languageKind, request, cancellationToken).ConfigureAwait(false); if (result is not null) @@ -107,7 +107,7 @@ protected AbstractTextDocumentPresentationEndpointBase( // For CSharp we need to map the range to the generated document if (languageKind == RazorLanguageKind.CSharp) { - if (!_razorDocumentMappingService.TryMapToGeneratedDocumentRange(codeDocument.GetCSharpDocument(), request.Range, out var projectedRange)) + if (!_documentMappingService.TryMapToGeneratedDocumentRange(codeDocument.GetCSharpDocument(), request.Range, out var projectedRange)) { return null; } @@ -233,7 +233,7 @@ private TextEdit[] MapTextEdits(bool mapRanges, RazorCodeDocument codeDocument, using var mappedEdits = new PooledArrayBuilder(); foreach (var edit in edits) { - if (!_razorDocumentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), edit.Range, out var newRange)) + if (!_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), edit.Range, out var newRange)) { return []; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs index 69aea0a8c69..c01cc3dbe92 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs @@ -15,11 +15,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal class TextDocumentTextPresentationEndpoint( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, ILoggerFactory loggerFactory) - : AbstractTextDocumentPresentationEndpointBase(razorDocumentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentTextPresentationHandler + : AbstractTextDocumentPresentationEndpointBase(documentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentTextPresentationHandler { public override string EndpointName => CustomMessageNames.RazorTextPresentationEndpoint; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs index 72cf2558498..cb8937d4a19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs @@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal class TextDocumentUriPresentationEndpoint( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, IDocumentContextFactory documentContextFactory, ILoggerFactory loggerFactory) - : AbstractTextDocumentPresentationEndpointBase(razorDocumentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentUriPresentationHandler + : AbstractTextDocumentPresentationEndpointBase(documentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentUriPresentationHandler { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs index e64bb4e1df1..6a783934424 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentSymbols; internal class DocumentSymbolEndpoint : IRazorRequestHandler?>, ICapabilitiesProvider { private readonly IClientConnection _clientConnection; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; public DocumentSymbolEndpoint( IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions) { _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); @@ -62,7 +62,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentSymbolParams req return null; } - var delegatedParams = new DelegatedDocumentSymbolParams(documentContext.Identifier); + var delegatedParams = new DelegatedDocumentSymbolParams(documentContext.GetTextDocumentIdentifierAndVersion()); var result = await _clientConnection.SendRequestAsync?>( CustomMessageNames.RazorDocumentSymbolEndpoint, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs new file mode 100644 index 00000000000..da57af39f48 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs @@ -0,0 +1,157 @@ +// 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 System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.AspNetCore.Razor.LanguageServer; + +internal sealed class EditMappingService( + IDocumentMappingService documentMappingService, + IFilePathService filePathService, + IDocumentContextFactory documentContextFactory) : IEditMappingService +{ + private readonly IDocumentMappingService _documentMappingService = documentMappingService; + private readonly IFilePathService _filePathService = filePathService; + private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; + + public async Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) + { + if (workspaceEdit.TryGetDocumentChanges(out var documentChanges)) + { + // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available. + var remappedEdits = await RemapVersionedDocumentEditsAsync(documentChanges, cancellationToken).ConfigureAwait(false); + + return new WorkspaceEdit() + { + DocumentChanges = remappedEdits + }; + } + + if (workspaceEdit.Changes is { } changeMap) + { + var remappedEdits = await RemapDocumentEditsAsync(changeMap, cancellationToken).ConfigureAwait(false); + + return new WorkspaceEdit() + { + Changes = remappedEdits + }; + } + + return workspaceEdit; + } + + private async Task RemapVersionedDocumentEditsAsync(TextDocumentEdit[] documentEdits, CancellationToken cancellationToken) + { + using var remappedDocumentEdits = new PooledArrayBuilder(documentEdits.Length); + + foreach (var entry in documentEdits) + { + var generatedDocumentUri = entry.TextDocument.Uri; + + // Check if the edit is actually for a generated document, because if not we don't need to do anything + if (!_filePathService.IsVirtualDocumentUri(generatedDocumentUri)) + { + // This location doesn't point to a background razor file. No need to remap. + remappedDocumentEdits.Add(entry); + continue; + } + + var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); + + if (!_documentContextFactory.TryCreateForOpenDocument(razorDocumentUri, entry.TextDocument.GetProjectContext(), out var documentContext)) + { + continue; + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + + var remappedEdits = RemapTextEditsCore(generatedDocumentUri, codeDocument, entry.Edits); + if (remappedEdits.Length == 0) + { + // Nothing to do. + continue; + } + + remappedDocumentEdits.Add(new() + { + TextDocument = new OptionalVersionedTextDocumentIdentifier() + { + Uri = razorDocumentUri, + Version = documentContext.Version + }, + Edits = remappedEdits + }); + } + + return remappedDocumentEdits.ToArray(); + } + + private async Task> RemapDocumentEditsAsync(Dictionary changes, CancellationToken cancellationToken) + { + var remappedChanges = new Dictionary(capacity: changes.Count); + + foreach (var (uriString, edits) in changes) + { + var uri = new Uri(uriString); + + // Check if the edit is actually for a generated document, because if not we don't need to do anything + if (!_filePathService.IsVirtualDocumentUri(uri)) + { + remappedChanges[uriString] = edits; + continue; + } + + if (!_documentContextFactory.TryCreate(uri, out var documentContext)) + { + continue; + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + var remappedEdits = RemapTextEditsCore(uri, codeDocument, edits); + if (remappedEdits.Length == 0) + { + // Nothing to do. + continue; + } + + var razorDocumentUri = _filePathService.GetRazorDocumentUri(uri); + remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits; + } + + return remappedChanges; + } + + private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocument codeDocument, TextEdit[] edits) + { + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, _filePathService, out var generatedDocument)) + { + return edits; + } + + using var remappedEdits = new PooledArrayBuilder(edits.Length); + + foreach (var edit in edits) + { + var generatedRange = edit.Range; + if (!_documentMappingService.TryMapToHostDocumentRange(generatedDocument, generatedRange, MappingBehavior.Strict, out var hostDocumentRange)) + { + // Can't map range. Discard this edit. + continue; + } + + var remappedEdit = VsLspFactory.CreateTextEdit(hostDocumentRange, edit.NewText); + remappedEdits.Add(remappedEdit); + } + + return remappedEdits.ToArray(); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index ad0a81ca49b..be6e74d6c5d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -202,7 +202,8 @@ public static void AddDocumentManagementServices(this IServiceCollection service services.AddSingleton(); services.AddSingleton((services) => (RazorProjectService)services.GetRequiredService()); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs index b3b9da23856..ccd2e6e93a1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs @@ -23,11 +23,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.FindAllReferences; internal sealed class FindAllReferencesEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { private readonly IFilePathService _filePathService; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public FindAllReferencesEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory, IFilePathService filePathService) @@ -67,9 +67,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override async Task HandleDelegatedResponseAsync(VSInternalReferenceItem[] delegatedResponse, ReferenceParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs index 47089246f24..f87c51192c1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs @@ -19,11 +19,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -internal sealed class CSharpFormatter(IRazorDocumentMappingService documentMappingService) +internal sealed class CSharpFormatter(IDocumentMappingService documentMappingService) { private const string MarkerId = "RazorMarker"; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public async Task FormatAsync(FormattingContext context, Range rangeToFormat, CancellationToken cancellationToken) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs index ae44807e53d..7db855f9bd1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class CSharpFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : CSharpFormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs index ab97332f801..590189a5362 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal abstract class CSharpFormattingPassBase : FormattingPassBase { - protected CSharpFormattingPassBase(IRazorDocumentMappingService documentMappingService) + protected CSharpFormattingPassBase(IDocumentMappingService documentMappingService) : base(documentMappingService) { CSharpFormatter = new CSharpFormatter(documentMappingService); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs index 1c60b4fa464..bad1194d899 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class CSharpOnTypeFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : CSharpFormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs index 71389874fcc..77c5b6a37ae 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs @@ -20,13 +20,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; [RazorLanguageServerEndpoint(Methods.TextDocumentOnTypeFormattingName)] internal class DocumentOnTypeFormattingEndpoint( IRazorFormattingService razorFormattingService, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerFactory) : IRazorRequestHandler, ICapabilitiesProvider { private readonly IRazorFormattingService _razorFormattingService = razorFormattingService ?? throw new ArgumentNullException(nameof(razorFormattingService)); - private readonly IRazorDocumentMappingService _razorDocumentMappingService = razorDocumentMappingService ?? throw new ArgumentNullException(nameof(razorDocumentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); @@ -95,7 +95,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentOnTypeFormatting return null; } - var triggerCharacterKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); + var triggerCharacterKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); if (triggerCharacterKind is not (RazorLanguageKind.CSharp or RazorLanguageKind.Html)) { _logger.LogInformation($"Unsupported trigger character language {triggerCharacterKind:G}."); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs index ec990b20f27..ff1eccb1f1c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class FormattingContentValidationPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs index ed7d5014b05..8f7cfda5c60 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class FormattingDiagnosticValidationPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs index 79a5af2ee64..8f0f6e1dc86 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -internal abstract class FormattingPassBase(IRazorDocumentMappingService documentMappingService) : IFormattingPass +internal abstract class FormattingPassBase(IDocumentMappingService documentMappingService) : IFormattingPass { protected static readonly int DefaultOrder = 1000; @@ -20,7 +20,7 @@ internal abstract class FormattingPassBase(IRazorDocumentMappingService document public virtual int Order => DefaultOrder; - protected IRazorDocumentMappingService DocumentMappingService { get; } = documentMappingService; + protected IDocumentMappingService DocumentMappingService { get; } = documentMappingService; public abstract Task ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs index 988494d9858..f522ea5790c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class HtmlFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IDocumentVersionCache documentVersionCache, ILoggerFactory loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs index d4d86a468c9..0fe7872f2d9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class RazorFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorLSPOptionsMonitor optionsMonitor) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs index 007250d2bdd..7989815323b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs @@ -153,7 +153,7 @@ private async Task ApplyFormattedEditsAsync( collapseEdits |= formattedEdits.Length == 1; var documentSnapshot = documentContext.Snapshot; - var uri = documentContext.Identifier.Uri; + var uri = documentContext.Uri; var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); using var context = FormattingContext.CreateForOnTypeFormatting(uri, documentSnapshot, codeDocument, options, _workspaceFactory, automaticallyAddUsings: automaticallyAddUsings, hostDocumentIndex, triggerCharacter); var result = new FormattingResult(formattedEdits, kind); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs index 956c0fec725..82455da7d44 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs @@ -23,7 +23,7 @@ internal sealed class HoverEndpoint : AbstractRazorDelegatingEndpoint()) @@ -51,9 +51,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override Task TryHandleAsync(TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs index fe063b11312..4fb546a09d6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs @@ -27,12 +27,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover; internal sealed partial class HoverService( LSPTagHelperTooltipFactory lspTagHelperTooltipFactory, VSLSPTagHelperTooltipFactory vsLspTagHelperTooltipFactory, - IRazorDocumentMappingService mappingService, + IDocumentMappingService documentMappingService, IClientCapabilitiesService clientCapabilitiesService) : IHoverService { private readonly LSPTagHelperTooltipFactory _lspTagHelperTooltipFactory = lspTagHelperTooltipFactory; private readonly VSLSPTagHelperTooltipFactory _vsLspTagHelperTooltipFactory = vsLspTagHelperTooltipFactory; - private readonly IRazorDocumentMappingService _mappingService = mappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IClientCapabilitiesService _clientCapabilitiesService = clientCapabilitiesService; public async Task GetRazorHoverInfoAsync(VersionedDocumentContext documentContext, DocumentPositionInfo positionInfo, Position position, CancellationToken cancellationToken) @@ -48,7 +48,7 @@ internal sealed partial class HoverService( // Sometimes what looks like a html attribute can actually map to C#, in which case its better to let Roslyn try to handle this. // We can only do this if we're in single server mode though, otherwise we won't be delegating to Roslyn at all - if (_mappingService.TryMapToGeneratedDocumentPosition(codeDocument.GetCSharpDocument(), positionInfo.HostDocumentIndex, out _, out _)) + if (_documentMappingService.TryMapToGeneratedDocumentPosition(codeDocument.GetCSharpDocument(), positionInfo.HostDocumentIndex, out _, out _)) { return null; } @@ -76,7 +76,7 @@ internal sealed partial class HoverService( } else if (positionInfo.LanguageKind == RazorLanguageKind.CSharp) { - if (_mappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), response.Range, out var projectedRange)) + if (_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), response.Range, out var projectedRange)) { response.Range = projectedRange; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs new file mode 100644 index 00000000000..57a1d184ab4 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs @@ -0,0 +1,55 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using LspRange = Microsoft.VisualStudio.LanguageServer.Protocol.Range; + +namespace Microsoft.AspNetCore.Razor.LanguageServer; + +internal static class IDocumentMappingServiceExtensions +{ + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + if (service is LspDocumentMappingService lspService) + { + return lspService.MapToHostDocumentUriAndRangeAsync(generatedDocumentUri, generatedDocumentRange, cancellationToken); + } + + return Assumed.Unreachable>(); + } + + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static async Task<(Uri MappedDocumentUri, LspRange MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + Uri generatedDocumentUri, + LspRange generatedDocumentRange, + CancellationToken cancellationToken) + { + var (mappedDocumentUri, mappedRange) = await service + .MapToHostDocumentUriAndRangeAsync( + generatedDocumentUri, + generatedDocumentRange.ToLinePositionSpan(), + cancellationToken) + .ConfigureAwait(false); + + return (mappedDocumentUri, mappedRange.ToRange()); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs index c575fc47796..dc7b13c4880 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal interface IDocumentPositionInfoStrategy { Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs index fc5c3807078..a2e89c2bbf7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs @@ -21,11 +21,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Implementation; [RazorLanguageServerEndpoint(Methods.TextDocumentImplementationName)] internal sealed class ImplementationEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public ImplementationEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : base(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()) @@ -53,9 +53,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected async override Task HandleDelegatedResponseAsync(ImplementationResult delegatedResponse, TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs index c0debade37d..294a6adc827 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs @@ -18,9 +18,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.InlayHints; -internal sealed class InlayHintService(IRazorDocumentMappingService documentMappingService) : IInlayHintService +internal sealed class InlayHintService(IDocumentMappingService documentMappingService) : IInlayHintService { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public async Task GetInlayHintsAsync(IClientConnection clientConnection, VersionedDocumentContext documentContext, Range range, CancellationToken cancellationToken) { @@ -42,7 +42,7 @@ internal sealed class InlayHintService(IRazorDocumentMappingService documentMapp // For now we only support C# inlay hints. Once Web Tools adds support we'll need to request from both servers and combine // the results, much like folding ranges. var delegatedRequest = new DelegatedInlayHintParams( - Identifier: documentContext.Identifier, + Identifier: documentContext.GetTextDocumentIdentifierAndVersion(), ProjectedRange: projectedLinePositionSpan.ToRange(), ProjectedKind: RazorLanguageKind.CSharp ); @@ -78,7 +78,7 @@ internal sealed class InlayHintService(IRazorDocumentMappingService documentMapp hint.Data = new RazorInlayHintWrapper { - TextDocument = documentContext.Identifier, + TextDocument = documentContext.GetTextDocumentIdentifierAndVersion(), OriginalData = hint.Data, OriginalPosition = hint.Position }; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs index 9593b528e87..0a452d66217 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.InlineCompletion; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentInlineCompletionName)] internal sealed class InlineCompletionEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IAdhocWorkspaceFactory adhocWorkspaceFactory, ILoggerFactory loggerFactory) @@ -36,7 +36,7 @@ internal sealed class InlineCompletionEndpoint( "if", "indexer", "interface", "invoke", "iterator", "iterindex", "lock", "mbox", "namespace", "#if", "#region", "prop", "propfull", "propg", "sim", "struct", "svm", "switch", "try", "tryf", "unchecked", "unsafe", "using", "while"); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); private readonly IAdhocWorkspaceFactory _adhocWorkspaceFactory = adhocWorkspaceFactory ?? throw new ArgumentNullException(nameof(adhocWorkspaceFactory)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs new file mode 100644 index 00000000000..23df0beeb18 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs @@ -0,0 +1,62 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.Logging; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.AspNetCore.Razor.LanguageServer; + +internal sealed class LspDocumentMappingService( + IFilePathService filePathService, + IDocumentContextFactory documentContextFactory, + ILoggerFactory loggerFactory) + : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) +{ + private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; + + public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + var razorDocumentUri = FilePathService.GetRazorDocumentUri(generatedDocumentUri); + + // For Html we just map the Uri, the range will be the same + if (FilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + return (razorDocumentUri, generatedDocumentRange); + } + + // We only map from C# files + if (!FilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + if (!_documentContextFactory.TryCreate(razorDocumentUri, out var documentContext)) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) + { + return Assumed.Unreachable<(Uri, LinePositionSpan)>(); + } + + if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) + { + return (razorDocumentUri, mappedRange); + } + + return (generatedDocumentUri, generatedDocumentRange); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index f076c975592..e38ace89ca0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -37,12 +37,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.MapCode; /// [RazorLanguageServerEndpoint(VSInternalMethods.WorkspaceMapCodeName)] internal sealed class MapCodeEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, ITelemetryReporter telemetryReporter) : IRazorDocumentlessRequestHandler, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); private readonly ITelemetryReporter _telemetryReporter = telemetryReporter ?? throw new ArgumentNullException(nameof(telemetryReporter)); @@ -202,7 +202,7 @@ private async Task TryMapCodeAsync( } var csharpMappingSuccessful = await TrySendCSharpDelegatedMappingRequestAsync( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), csharpBody, csharpFocusLocations, mapCodeCorrelationId, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs index b4e6da2b476..62f55e00a19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs @@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Mapping; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorLanguageQueryEndpoint)] -internal sealed class RazorLanguageQueryEndpoint(IRazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) +internal sealed class RazorLanguageQueryEndpoint(IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : IRazorRequestHandler { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool MutatesSolutionState { get; } = false; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs index 18f308dc13c..a6e0c6f6a29 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs @@ -20,9 +20,9 @@ internal sealed class RazorMapToDocumentRangesEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; - public RazorMapToDocumentRangesEndpoint(IRazorDocumentMappingService documentMappingService) + public RazorMapToDocumentRangesEndpoint(IDocumentMappingService documentMappingService) { _documentMappingService = documentMappingService; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs index 3bd88203f85..98b8fcac5d1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs @@ -20,7 +20,7 @@ internal class PreferAttributeNameDocumentPositionInfoStrategy : IDocumentPositi public static IDocumentPositionInfoStrategy Instance { get; } = new PreferAttributeNameDocumentPositionInfoStrategy(); public async Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs deleted file mode 100644 index 61d7886acef..00000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; - -namespace Microsoft.AspNetCore.Razor.LanguageServer; - -internal sealed class RazorDocumentMappingService( - IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, - ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService(filePathService, documentContextFactory, loggerFactory.GetOrCreateLogger()) -{ -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index d28f56bcb24..6960617a980 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -30,7 +30,8 @@ internal sealed class RenameEndpoint( IRazorComponentSearchEngine componentSearchEngine, IProjectCollectionResolver projectResolver, LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, + IEditMappingService editMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint( @@ -42,7 +43,7 @@ internal sealed class RenameEndpoint( private readonly IProjectCollectionResolver _projectResolver = projectResolver; private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities) { @@ -91,10 +92,10 @@ protected override bool IsSupported() } return Task.FromResult(new DelegatedRenameParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind, - request.NewName)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind, + request.NewName)); } protected override async Task HandleDelegatedResponseAsync(WorkspaceEdit? response, RenameParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) @@ -104,7 +105,7 @@ protected override bool IsSupported() return null; } - return await _documentMappingService.RemapWorkspaceEditAsync(response, cancellationToken).ConfigureAwait(false); + return await _editMappingService.RemapWorkspaceEditAsync(response, cancellationToken).ConfigureAwait(false); } private async Task TryGetRazorComponentRenameEditsAsync(RenameParams request, int absoluteIndex, DocumentContext documentContext, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs index 841b15ba463..6a2e9d8dceb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs @@ -41,7 +41,12 @@ internal class LSPCSharpSemanticTokensProvider(LanguageServerFeatureOptions lang var csharpRanges = csharpRangeList.ToArray(); - var parameter = new ProvideSemanticTokensRangesParams(documentContext.Identifier.TextDocumentIdentifier, documentVersion, csharpRanges, correlationId); + var parameter = new ProvideSemanticTokensRangesParams( + documentContext.GetTextDocumentIdentifierAndVersion().TextDocumentIdentifier, + documentVersion, + csharpRanges, + correlationId); + ProvideSemanticTokensResponse? csharpResponse; if (_languageServerFeatureOptions.UsePreciseSemanticTokenRanges) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs index 4a2bd4da4e4..507671b5527 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; internal class RazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs index 790cd537f07..e7c488771e3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp; [RazorLanguageServerEndpoint(Methods.TextDocumentSignatureHelpName)] internal sealed class SignatureHelpEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerProvider) @@ -54,8 +54,8 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs index ca84457a042..3d2b69e43a5 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.SpellCheck; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentSpellCheckableRangesName)] internal sealed class DocumentSpellCheckEndpoint : IRazorRequestHandler, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly IClientConnection _clientConnection; public DocumentSpellCheckEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection) { @@ -129,7 +129,7 @@ MarkupMinimizedTagHelperDirectiveAttributeSyntax or private async Task AddCSharpSpellCheckRangesAsync(List ranges, VersionedDocumentContext documentContext, CancellationToken cancellationToken) { - var delegatedParams = new DelegatedSpellCheckParams(documentContext.Identifier); + var delegatedParams = new DelegatedSpellCheckParams(documentContext.GetTextDocumentIdentifierAndVersion()); var delegatedResponse = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSpellCheckEndpoint, delegatedParams, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs index b290be86aef..990dbc07a6e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs @@ -20,12 +20,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorWrapWithTagEndpoint)] internal class WrapWithTagEndpoint( IClientConnection clientConnection, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : IRazorRequestHandler { private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); - private readonly IRazorDocumentMappingService _razorDocumentMappingService = razorDocumentMappingService ?? throw new ArgumentNullException(nameof(razorDocumentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool MutatesSolutionState => false; @@ -69,7 +69,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(WrapWithTagParams reques // // Instead of C#, which certainly would be expected to go in an if statement, we'll see HTML, which obviously // is the better choice for this operation. - var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: true); + var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: true); if (languageKind is not RazorLanguageKind.Html) { // In general, we don't support C# for obvious reasons, but we can support implicit expressions. ie diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs similarity index 80% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs index 56e0a854e44..60949687b5e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs @@ -6,15 +6,12 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; @@ -22,15 +19,10 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal abstract class AbstractRazorDocumentMappingService( - IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, - ILogger logger) - : IRazorDocumentMappingService +internal abstract class AbstractDocumentMappingService(IFilePathService filePathService, ILogger logger) : IDocumentMappingService { - private readonly IFilePathService _documentFilePathService = filePathService ?? throw new ArgumentNullException(nameof(filePathService)); - private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); - private readonly ILogger _logger = logger; + protected readonly IFilePathService FilePathService = filePathService; + protected readonly ILogger Logger = logger; public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentChanges) { @@ -202,7 +194,7 @@ public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocu (hostDocumentRange.End.Line == hostDocumentRange.Start.Line && hostDocumentRange.End.Character < hostDocumentRange.Start.Character)) { - _logger.LogWarning($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); + Logger.LogWarning($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); Debug.Fail($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); return false; } @@ -359,64 +351,6 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos return languageKind; } - public async Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) - { - if (workspaceEdit.TryGetDocumentChanges(out var documentChanges)) - { - // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available. - var remappedEdits = await RemapVersionedDocumentEditsAsync(documentChanges, cancellationToken).ConfigureAwait(false); - return new WorkspaceEdit() - { - DocumentChanges = remappedEdits - }; - } - else if (workspaceEdit.Changes != null) - { - var remappedEdits = await RemapDocumentEditsAsync(workspaceEdit.Changes, cancellationToken).ConfigureAwait(false); - return new WorkspaceEdit() - { - Changes = remappedEdits - }; - } - - return workspaceEdit; - } - - public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken) - { - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(generatedDocumentUri); - - // For Html we just map the Uri, the range will be the same - if (_documentFilePathService.IsVirtualHtmlFile(generatedDocumentUri)) - { - return (razorDocumentUri, generatedDocumentRange); - } - - // We only map from C# files - if (!_documentFilePathService.IsVirtualCSharpFile(generatedDocumentUri)) - { - return (generatedDocumentUri, generatedDocumentRange); - } - - if (!_documentContextFactory.TryCreate(razorDocumentUri, out var documentContext)) - { - return (generatedDocumentUri, generatedDocumentRange); - } - - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); - - // We already checked that the uri was for a generated document, above - Assumes.NotNull(generatedDocument); - - if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) - { - return (razorDocumentUri, mappedRange); - } - - return (generatedDocumentUri, generatedDocumentRange); - } - // Internal for testing internal static RazorLanguageKind GetLanguageKindCore( ImmutableArray classifiedSpans, @@ -722,7 +656,7 @@ private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText { s_haveAsserted = true; var sourceTextLinesCount = sourceText.Lines.Count; - _logger.LogWarning($"Attempted to map a range ({range.Start.Line},{range.Start.Character})-({range.End.Line},{range.End.Character}) outside of the Source (line count {sourceTextLinesCount}.) This could happen if the Roslyn and Razor LSP servers are not in sync."); + Logger.LogWarning($"Attempted to map a range ({range.Start.Line},{range.Start.Character})-({range.End.Line},{range.End.Character}) outside of the Source (line count {sourceTextLinesCount}.) This could happen if the Roslyn and Razor LSP servers are not in sync."); } return result; @@ -733,127 +667,6 @@ static bool IsPositionWithinDocument(LinePosition linePosition, SourceText sourc } } - private async Task RemapVersionedDocumentEditsAsync(TextDocumentEdit[] documentEdits, CancellationToken cancellationToken) - { - using var _ = ListPool.GetPooledObject(out var remappedDocumentEdits); - foreach (var entry in documentEdits) - { - var generatedDocumentUri = entry.TextDocument.Uri; - - // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_documentFilePathService.IsVirtualDocumentUri(generatedDocumentUri)) - { - // This location doesn't point to a background razor file. No need to remap. - remappedDocumentEdits.Add(entry); - continue; - } - - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(generatedDocumentUri); - - if (!_documentContextFactory.TryCreateForOpenDocument(razorDocumentUri, entry.TextDocument.GetProjectContext(), out var documentContext)) - { - continue; - } - - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - - var remappedEdits = RemapTextEditsCore(generatedDocumentUri, codeDocument, entry.Edits); - if (remappedEdits.Length == 0) - { - // Nothing to do. - continue; - } - - remappedDocumentEdits.Add(new TextDocumentEdit() - { - TextDocument = new OptionalVersionedTextDocumentIdentifier() - { - Uri = razorDocumentUri, - Version = documentContext.Version - }, - Edits = remappedEdits - }); - } - - return [.. remappedDocumentEdits]; - } - - private async Task> RemapDocumentEditsAsync(Dictionary changes, CancellationToken cancellationToken) - { - var remappedChanges = new Dictionary(); - foreach (var entry in changes) - { - var uri = new Uri(entry.Key); - var edits = entry.Value; - - // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_documentFilePathService.IsVirtualDocumentUri(uri)) - { - remappedChanges[entry.Key] = entry.Value; - continue; - } - - if (!_documentContextFactory.TryCreate(uri, out var documentContext)) - { - continue; - } - - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var remappedEdits = RemapTextEditsCore(uri, codeDocument, edits); - if (remappedEdits.Length == 0) - { - // Nothing to do. - continue; - } - - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(uri); - remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits; - } - - return remappedChanges; - } - - private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocument codeDocument, TextEdit[] edits) - { - var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); - if (generatedDocument is null) - { - return edits; - } - - using var _ = ListPool.GetPooledObject(out var remappedEdits); - for (var i = 0; i < edits.Length; i++) - { - var generatedRange = edits[i].Range; - if (!this.TryMapToHostDocumentRange(generatedDocument, generatedRange, MappingBehavior.Strict, out var originalRange)) - { - // Can't map range. Discard this edit. - continue; - } - - var edit = VsLspFactory.CreateTextEdit(originalRange, edits[i].NewText); - remappedEdits.Add(edit); - } - - return [.. remappedEdits]; - } - - private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) - { - if (_documentFilePathService.IsVirtualCSharpFile(generatedDocumentUri)) - { - return codeDocument.GetCSharpDocument(); - } - else if (_documentFilePathService.IsVirtualHtmlFile(generatedDocumentUri)) - { - return codeDocument.GetHtmlDocument(); - } - else - { - return null; - } - } - private static ImmutableArray GetClassifiedSpans(RazorCodeDocument document) { // Since this service is called so often, we get a good performance improvement by caching these values diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs similarity index 64% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs index 4cbdb21a09b..486a7e28a67 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs @@ -1,18 +1,14 @@ // 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 System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal interface IRazorDocumentMappingService +internal interface IDocumentMappingService { IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentEdits); @@ -27,13 +23,4 @@ internal interface IRazorDocumentMappingService bool TryMapToGeneratedDocumentOrNextCSharpPosition(IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, out LinePosition generatedPosition, out int generatedIndex); RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hostDocumentIndex, bool rightAssociative); - - Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken); - - /// - /// Maps a range in the specified generated document uri to a range in the Razor document that owns the - /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped - /// for some other reason, the original passed in range is returned unchanged. - /// - Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs similarity index 63% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs index 9ead7ef2509..f592d5e12ee 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -1,7 +1,6 @@ // 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.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -16,9 +15,9 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal static class IRazorDocumentMappingServiceExtensions +internal static class IDocumentMappingServiceExtensions { - public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) + public static TextEdit[] GetHostDocumentEdits(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) { var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); var documentText = generatedDocument.CodeDocument.AssumeNotNull().Source.Text; @@ -28,13 +27,13 @@ public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService return mappedChanges.Select(documentText.GetTextEdit).ToArray(); } - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) => service.TryMapToHostDocumentRange(generatedDocument, projectedRange, MappingBehavior.Strict, out originalRange); - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range projectedRange, [NotNullWhen(true)] out Range? originalRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range projectedRange, [NotNullWhen(true)] out Range? originalRange) => service.TryMapToHostDocumentRange(generatedDocument, projectedRange, MappingBehavior.Strict, out originalRange); - public static async Task GetPositionInfoAsync(this IRazorDocumentMappingService service, DocumentContext documentContext, int hostDocumentIndex, CancellationToken cancellationToken) + public static async Task GetPositionInfoAsync(this IDocumentMappingService service, DocumentContext documentContext, int hostDocumentIndex, CancellationToken cancellationToken) { var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); @@ -43,7 +42,7 @@ public static async Task GetPositionInfoAsync(this IRazorD } public static DocumentPositionInfo GetPositionInfo( - this IRazorDocumentMappingService service, + this IDocumentMappingService service, RazorCodeDocument codeDocument, SourceText sourceText, int hostDocumentIndex) @@ -74,49 +73,38 @@ public static DocumentPositionInfo GetPositionInfo( return new DocumentPositionInfo(languageKind, position, hostDocumentIndex); } - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range generatedDocumentRange, MappingBehavior mappingBehavior, [NotNullWhen(true)] out Range? hostDocumentRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range generatedDocumentRange, MappingBehavior mappingBehavior, [NotNullWhen(true)] out Range? hostDocumentRange) { var result = service.TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange.ToLinePositionSpan(), mappingBehavior, out var hostDocumentLinePositionSpan); hostDocumentRange = result ? hostDocumentLinePositionSpan.ToRange() : null; return result; } - public static bool TryMapToGeneratedDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range hostDocumentRange, [NotNullWhen(true)] out Range? generatedDocumentRange) + public static bool TryMapToGeneratedDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range hostDocumentRange, [NotNullWhen(true)] out Range? generatedDocumentRange) { var result = service.TryMapToGeneratedDocumentRange(generatedDocument, hostDocumentRange.ToLinePositionSpan(), out var generatedDocumentLinePositionSpan); generatedDocumentRange = result ? generatedDocumentLinePositionSpan.ToRange() : null; return result; } - public static bool TryMapToHostDocumentPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int generatedDocumentIndex, [NotNullWhen(true)] out Position? hostDocumentPosition, out int hostDocumentIndex) + public static bool TryMapToHostDocumentPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int generatedDocumentIndex, [NotNullWhen(true)] out Position? hostDocumentPosition, out int hostDocumentIndex) { var result = service.TryMapToHostDocumentPosition(generatedDocument, generatedDocumentIndex, out var hostDocumentLinePosition, out hostDocumentIndex); hostDocumentPosition = result ? hostDocumentLinePosition.ToPosition() : null; return result; } - public static bool TryMapToGeneratedDocumentPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) + public static bool TryMapToGeneratedDocumentPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) { var result = service.TryMapToGeneratedDocumentPosition(generatedDocument, hostDocumentIndex, out var generatedLinePosition, out generatedIndex); generatedPosition = result ? generatedLinePosition.ToPosition() : null; return result; } - public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) + public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) { var result = service.TryMapToGeneratedDocumentOrNextCSharpPosition(generatedDocument, hostDocumentIndex, out var generatedLinePosition, out generatedIndex); generatedPosition = result ? generatedLinePosition.ToPosition() : null; return result; } - - /// - /// Maps a range in the specified generated document uri to a range in the Razor document that owns the - /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped - /// for some other reason, the original passed in range is returned unchanged. - /// - public static async Task<(Uri MappedDocumentUri, Range MappedRange)> MapToHostDocumentUriAndRangeAsync(this IRazorDocumentMappingService service, Uri generatedDocumentUri, Range generatedDocumentRange, CancellationToken cancellationToken) - { - var result = await service.MapToHostDocumentUriAndRangeAsync(generatedDocumentUri, generatedDocumentRange.ToLinePositionSpan(), cancellationToken).ConfigureAwait(false); - return (result.MappedDocumentUri, result.MappedRange.ToRange()); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs new file mode 100644 index 00000000000..1cf7c098da4 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs @@ -0,0 +1,13 @@ +// 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.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; + +internal interface IEditMappingService +{ + Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs index c542c6e3cf3..8341fe945df 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs @@ -1,11 +1,14 @@ // 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.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.Language; @@ -43,6 +46,28 @@ public static SourceText GetHtmlSourceText(this RazorCodeDocument document) return sourceText.AssumeNotNull(); } + public static bool TryGetGeneratedDocument( + this RazorCodeDocument codeDocument, + Uri generatedDocumentUri, + IFilePathService filePathService, + [NotNullWhen(true)] out IRazorGeneratedDocument? generatedDocument) + { + if (filePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + generatedDocument = codeDocument.GetCSharpDocument(); + return true; + } + + if (filePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + generatedDocument = codeDocument.GetHtmlDocument(); + return true; + } + + generatedDocument = null; + return false; + } + public static SourceText GetGeneratedSourceText(this RazorCodeDocument document, IRazorGeneratedDocument generatedDocument) => generatedDocument switch { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs index 537828f3a09..9aaf5b9a5c9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs @@ -1,19 +1,25 @@ // 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.Immutable; using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor; namespace Microsoft.CodeAnalysis; internal static class SolutionExtensions { - internal static Project GetRequiredProject(this Solution solution, ProjectId projectId) + public static ImmutableArray GetDocumentIdsWithUri(this Solution solution, Uri uri) + => solution.GetDocumentIdsWithFilePath(uri.GetDocumentFilePath()); + + public static Project GetRequiredProject(this Solution solution, ProjectId projectId) { return solution.GetProject(projectId) ?? ThrowHelper.ThrowInvalidOperationException($"The projectId {projectId} did not exist in {solution}."); } - internal static Document GetRequiredDocument(this Solution solution, DocumentId documentId) + public static Document GetRequiredDocument(this Solution solution, DocumentId documentId) { return solution.GetDocument(documentId) ?? ThrowHelper.ThrowInvalidOperationException($"The document {documentId} did not exist in {solution.FilePath ?? "solution"}."); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs index def3567e4b3..194ccb94d8c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs @@ -17,12 +17,12 @@ namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; internal class FoldingRangeService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IEnumerable foldingRangeProviders, ILoggerFactory loggerFactory) : IFoldingRangeService { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IEnumerable _foldingRangeProviders = foldingRangeProviders; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs index 36a01ebd20f..a99c792531f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs @@ -2,117 +2,172 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; +using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.AspNetCore.Razor.Language.Syntax; - -internal class DocumentContext +internal class DocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext) { + private readonly VSProjectContext? _projectContext = projectContext; private RazorCodeDocument? _codeDocument; private SourceText? _sourceText; - private readonly VSProjectContext? _projectContext; - - public DocumentContext( - Uri uri, - IDocumentSnapshot snapshot, - VSProjectContext? projectContext) - { - Uri = uri; - Snapshot = snapshot; - _projectContext = projectContext; - } - - public virtual Uri Uri { get; } - - public virtual IDocumentSnapshot Snapshot { get; } - public virtual string FilePath => Snapshot.FilePath.AssumeNotNull(); + public Uri Uri { get; } = uri; + public IDocumentSnapshot Snapshot { get; } = snapshot; + public string FilePath => Snapshot.FilePath.AssumeNotNull(); + public string FileKind => Snapshot.FileKind.AssumeNotNull(); + public IProjectSnapshot Project => Snapshot.Project; - public virtual string FileKind => Snapshot.FileKind.AssumeNotNull(); - - public virtual IProjectSnapshot Project => Snapshot.Project; + public TextDocumentIdentifier GetTextDocumentIdentifier() + => new VSTextDocumentIdentifier() + { + Uri = Uri, + ProjectContext = _projectContext, + }; - public virtual TextDocumentIdentifier Identifier => new VSTextDocumentIdentifier() + private bool TryGetCodeDocument([NotNullWhen(true)] out RazorCodeDocument? codeDocument) { - Uri = Uri, - ProjectContext = _projectContext, - }; + codeDocument = _codeDocument; + return codeDocument is not null; + } - public virtual async Task GetCodeDocumentAsync(CancellationToken cancellationToken) + public ValueTask GetCodeDocumentAsync(CancellationToken cancellationToken) { - if (_codeDocument is null) + return TryGetCodeDocument(out var codeDocument) + ? new(codeDocument) + : GetCodeDocumentCoreAsync(cancellationToken); + + async ValueTask GetCodeDocumentCoreAsync(CancellationToken cancellationToken) { var codeDocument = await Snapshot.GetGeneratedOutputAsync().ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - _codeDocument = codeDocument; + // Interlock to ensure that we only ever return one instance of RazorCodeDocument. + // In race scenarios, when more than one RazorCodeDocument is produced, we want to + // return whichever RazorCodeDocument is cached. + return InterlockedOperations.Initialize(ref _codeDocument, codeDocument); } - - return _codeDocument; } - public virtual async Task GetSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetSourceTextAsync(CancellationToken cancellationToken) { - if (_sourceText is null) + return _sourceText is SourceText sourceText + ? new(sourceText) + : GetSourceTextCoreAsync(cancellationToken); + + async ValueTask GetSourceTextCoreAsync(CancellationToken cancellationToken) { var sourceText = await Snapshot.GetTextAsync().ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - _sourceText = sourceText; + // Interlock to ensure that we only ever return one instance of RazorCodeDocument. + // In race scenarios, when more than one RazorCodeDocument is produced, we want to + // return whichever RazorCodeDocument is cached. + return InterlockedOperations.Initialize(ref _sourceText, sourceText); } - - return _sourceText; } - public virtual async Task GetSyntaxTreeAsync(CancellationToken cancellationToken) + public ValueTask GetSyntaxTreeAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var syntaxTree = codeDocument.GetSyntaxTree(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetSyntaxTreeCore(codeDocument)) + : GetSyntaxTreeCoreAsync(cancellationToken); - return syntaxTree; + static RazorSyntaxTree GetSyntaxTreeCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetSyntaxTree().AssumeNotNull(); + } + + async ValueTask GetSyntaxTreeCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetSyntaxTreeCore(codeDocument); + } } - public virtual async Task GetTagHelperContextAsync(CancellationToken cancellationToken) + public ValueTask GetTagHelperContextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var tagHelperContext = codeDocument.GetTagHelperContext(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetTagHelperContextCore(codeDocument)) + : GetTagHelperContextCoreAsync(cancellationToken); - return tagHelperContext; + static TagHelperDocumentContext GetTagHelperContextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetTagHelperContext().AssumeNotNull(); + } + + async ValueTask GetTagHelperContextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetTagHelperContextCore(codeDocument); + } } - public virtual async Task GetCSharpSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetCSharpSourceTextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var sourceText = codeDocument.GetCSharpSourceText(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetCSharpSourceTextCore(codeDocument)) + : GetCSharpSourceTextCoreAsync(cancellationToken); - return sourceText; + static SourceText GetCSharpSourceTextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetCSharpSourceText(); + } + + async ValueTask GetCSharpSourceTextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetCSharpSourceTextCore(codeDocument); + } } - public virtual async Task GetHtmlSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetHtmlSourceTextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var sourceText = codeDocument.GetHtmlSourceText(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetHtmlSourceTextCore(codeDocument)) + : GetHtmlSourceTextCoreAsync(cancellationToken); - return sourceText; + static SourceText GetHtmlSourceTextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetHtmlSourceText(); + } + + async ValueTask GetHtmlSourceTextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetHtmlSourceTextCore(codeDocument); + } } - public async Task GetSyntaxNodeAsync(int absoluteIndex, CancellationToken cancellationToken) + public ValueTask GetSyntaxNodeAsync(int absoluteIndex, CancellationToken cancellationToken) { - var syntaxTree = await GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - if (syntaxTree.Root is null) + return TryGetCodeDocument(out var codeDocument) + ? new(GetSyntaxNodeCore(codeDocument, absoluteIndex)) + : GetSyntaxNodeCoreAsync(absoluteIndex, cancellationToken); + + static RazorSyntaxNode? GetSyntaxNodeCore(RazorCodeDocument codeDocument, int absoluteIndex) { - return null; + var syntaxTree = codeDocument.GetSyntaxTree().AssumeNotNull(); + + return syntaxTree.Root is RazorSyntaxNode root + ? root.FindInnermostNode(absoluteIndex) + : null; } - return syntaxTree.Root.FindInnermostNode(absoluteIndex); + async ValueTask GetSyntaxNodeCoreAsync(int absoluteIndex, CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetSyntaxNodeCore(codeDocument, absoluteIndex); + } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index 258f1d38b6b..a22e2c4d746 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -218,7 +218,7 @@ static void PropagateToTaskCompletionSource( var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false); var forceRuntimeCodeGeneration = project.Configuration.LanguageServerFlags?.ForceRuntimeCodeGeneration ?? false; - var codeDocument = await GenerateCodeDocumentAsync(tagHelpers, project.GetProjectEngine(), document, imports, forceRuntimeCodeGeneration).ConfigureAwait(false); + var codeDocument = await GenerateCodeDocumentAsync(document, project.GetProjectEngine(), imports, tagHelpers, forceRuntimeCodeGeneration).ConfigureAwait(false); return (codeDocument, inputVersion); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 4055cd936f9..859673968b2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -265,7 +265,7 @@ internal static ImmutableArray GetImportsCore(IProjectSnapsho return imports.ToImmutable(); } - internal static async Task GenerateCodeDocumentAsync(ImmutableArray tagHelpers, RazorProjectEngine projectEngine, IDocumentSnapshot document, ImmutableArray imports, bool forceRuntimeCodeGeneration) + internal static async Task GenerateCodeDocumentAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, ImmutableArray imports, ImmutableArray tagHelpers, bool forceRuntimeCodeGeneration) { // OK we have to generate the code. using var importSources = new PooledArrayBuilder(imports.Length); @@ -287,9 +287,6 @@ internal static async Task GenerateCodeDocumentAsync(Immutabl return projectEngine.ProcessDesignTime(documentSource, fileKind: document.FileKind, importSources.DrainToImmutable(), tagHelpers); } - internal static Task GenerateFormattingCodeDocumentAsync(ImmutableArray tagHelpers, RazorProjectEngine projectEngine, IDocumentSnapshot document, ImmutableArray imports) - => GenerateCodeDocumentAsync(tagHelpers, projectEngine, document, imports, forceRuntimeCodeGeneration: false); - internal static async Task> GetImportsAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine) { var imports = GetImportsCore(document.Project, projectEngine, document.FilePath.AssumeNotNull(), document.FileKind.AssumeNotNull()); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs index 7e97774f9ed..ef8b26ca9e9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs @@ -82,6 +82,6 @@ private static async Task GetDesignTimeDocumentAsync(IDocumen var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false); var projectEngine = project.GetProjectEngine(); var imports = await DocumentState.GetImportsAsync(documentSnapshot, projectEngine).ConfigureAwait(false); - return await DocumentState.GenerateCodeDocumentAsync(tagHelpers, project.GetProjectEngine(), documentSnapshot, imports, false).ConfigureAwait(false); + return await DocumentState.GenerateCodeDocumentAsync(documentSnapshot, project.GetProjectEngine(), imports, tagHelpers, false).ConfigureAwait(false); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs index b203540027e..6c4bbcf8ade 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs @@ -7,18 +7,11 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal class VersionedDocumentContext : DocumentContext +internal class VersionedDocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext, int version) + : DocumentContext(uri, snapshot, projectContext) { - public virtual int Version { get; } + public int Version { get; } = version; - public VersionedDocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext, int version) - : base(uri, snapshot, projectContext) - { - Version = version; - } - - // Sadly we target net472 which doesn't support covariant return types, so this can't override. - public new TextDocumentIdentifierAndVersion Identifier => new TextDocumentIdentifierAndVersion( - base.Identifier, - Version); + public TextDocumentIdentifierAndVersion GetTextDocumentIdentifierAndVersion() + => new(GetTextDocumentIdentifier(), Version); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs index 2fa4acdd54d..712506f4e53 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Razor.SemanticTokens; internal abstract class AbstractRazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, @@ -29,7 +29,7 @@ internal abstract class AbstractRazorSemanticTokensInfoService( { private const int TokenSize = 5; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService; private readonly ICSharpSemanticTokensProvider _csharpSemanticTokensProvider = csharpSemanticTokensProvider; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs index c4e2063f81c..b1ae800478f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs @@ -4,11 +4,19 @@ using System; using System.Net; using Microsoft.AspNetCore.Razor.Utilities; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; namespace Microsoft.CodeAnalysis.Razor; internal static class UriExtensions { + /// + /// Converts the specified into a file path that matches + /// a Roslyn . + /// + public static string GetDocumentFilePath(this Uri uri) + => RazorUri.GetDocumentFilePathFromUri(uri); + public static string GetAbsoluteOrUNCPath(this Uri uri) { if (uri is null) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs index 61252f6d011..ec782be065c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs @@ -28,7 +28,7 @@ protected override IRemoteDocumentHighlightService CreateService(in ServiceArgs => new RemoteDocumentHighlightService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); public ValueTask GetHighlightsAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs new file mode 100644 index 00000000000..f51c649eb18 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -0,0 +1,60 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; +using RoslynRange = Roslyn.LanguageServer.Protocol.Range; + +namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; + +internal static class IDocumentMappingServiceExtensions +{ + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + if (service is RemoteDocumentMappingService remoteService) + { + return remoteService.MapToHostDocumentUriAndRangeAsync(originSnapshot, generatedDocumentUri, generatedDocumentRange, cancellationToken); + } + + return Assumed.Unreachable>(); + } + + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static async Task<(Uri MappedDocumentUri, RoslynRange MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + RoslynRange generatedDocumentRange, + CancellationToken cancellationToken) + { + var (mappedDocumentUri, mappedRange) = await service + .MapToHostDocumentUriAndRangeAsync( + originSnapshot, + generatedDocumentUri, + generatedDocumentRange.ToLinePositionSpan(), + cancellationToken) + .ConfigureAwait(false); + + return (mappedDocumentUri, mappedRange.ToRange()); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 746868a1236..a4b946fc645 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -1,23 +1,82 @@ // 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.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; -[Export(typeof(IRazorDocumentMappingService)), Shared] +[Export(typeof(IDocumentMappingService)), Shared] [method: ImportingConstructor] internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, + DocumentSnapshotFactory documentSnapshotFactory, ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService( - filePathService, - documentContextFactory, - loggerFactory.GetOrCreateLogger()) + : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { + private readonly DocumentSnapshotFactory _documentSnapshotFactory = documentSnapshotFactory; + + public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + var razorDocumentUri = FilePathService.GetRazorDocumentUri(generatedDocumentUri); + + // For Html we just map the Uri, the range will be the same + if (FilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + return (razorDocumentUri, generatedDocumentRange); + } + + // We only map from C# files + if (!FilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + var solution = originSnapshot.TextDocument.Project.Solution; + + var razorDocumentId = solution.GetDocumentIdsWithUri(razorDocumentUri).FirstOrDefault(); + + // If we couldn't locate the .razor file, just return the generated file. + if (razorDocumentId is null || + solution.GetAdditionalDocument(razorDocumentId) is not TextDocument razorDocument) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + var razorDocumentSnapshot = _documentSnapshotFactory.GetOrCreate(razorDocument); + + var razorCodeDocument = await razorDocumentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + + if (razorCodeDocument is null) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + if (!razorCodeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) + { + return Assumed.Unreachable<(Uri, LinePositionSpan)>(); + } + + if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) + { + return (razorDocumentUri, mappedRange); + } + + return (generatedDocumentUri, generatedDocumentRange); + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs index 67565c459a4..fcf9db1bdf7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.FoldingRanges; [Export(typeof(IFoldingRangeService)), Shared] [method: ImportingConstructor] internal sealed class OOPFoldingRangeService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, [ImportMany] IEnumerable foldingRangeProviders, ILoggerFactory loggerFactory) : FoldingRangeService(documentMappingService, foldingRangeProviders, loggerFactory) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs index 0bbb9c8fccd..ae06c498c58 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs @@ -27,7 +27,7 @@ protected override IRemoteInlayHintService CreateService(in ServiceArgs args) => new RemoteInlayHintService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); public ValueTask GetInlayHintsAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHintParams inlayHintParams, bool displayAllOverride, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs index 7ba739e1ba5..bd29cf52ab3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs @@ -14,44 +14,35 @@ namespace Microsoft.CodeAnalysis.Remote.Razor; internal static class DocumentContextExtensions { - public static async Task GetGeneratedDocumentAsync(this VersionedDocumentContext documentContext, IFilePathService filePathService, CancellationToken cancellationToken) + public static async Task GetGeneratedDocumentAsync( + this VersionedDocumentContext documentContext, + IFilePathService filePathService, + CancellationToken cancellationToken) { Debug.Assert(documentContext.Snapshot is RemoteDocumentSnapshot, "This method only works on document contexts created in the OOP process"); var snapshot = (RemoteDocumentSnapshot)documentContext.Snapshot; - if (snapshot.TryGetGeneratedDocument(out var generatedDocument)) - { - return generatedDocument; - } - - var razorDocument = snapshot.TextDocument; - var solution = razorDocument.Project.Solution; - - // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution + return await snapshot.GetOrAddGeneratedDocumentAsync( + (snapshot, documentContext, filePathService, cancellationToken), + static async arg => + { + var (snapshot, documentContext, filePathService, cancellationToken) = arg; - var projectKey = razorDocument.Project.ToProjectKey(); - var generatedFilePath = filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); - var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == razorDocument.Project.Id); - generatedDocument = solution.GetRequiredDocument(generatedDocumentId); + var razorDocument = snapshot.TextDocument; + var projectKey = snapshot.Project.Key; + var solution = razorDocument.Project.Solution; - var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); + // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution - // HACK: We're not in the same solution fork as the LSP server that provides content for this document - generatedDocument = generatedDocument.WithText(csharpSourceText); + var generatedFilePath = filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); + var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == razorDocument.Project.Id); + var generatedDocument = solution.GetRequiredDocument(generatedDocumentId); - // Obviously this lock is not sufficient to avoid wasted work, but it does at least avoid mutating the snapshot - // any more than just a once of caching of the generated document, which is what is really happening with the set - // method call below. - lock (snapshot) - { - if (snapshot.TryGetGeneratedDocument(out var generatedDocument2)) - { - return generatedDocument2; - } + var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); - snapshot.SetGeneratedDocument(generatedDocument); - return generatedDocument; - } + // HACK: We're not in the same solution fork as the LSP server that provides content for this document + return generatedDocument.WithText(csharpSourceText); + }); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs deleted file mode 100644 index a23e018bcd1..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.Composition; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; - -[Export(typeof(IDocumentContextFactory)), Shared] -internal class DocumentContextFactory : IDocumentContextFactory -{ - public bool TryCreate( - Uri documentUri, - VSProjectContext? projectContext, - bool versioned, - [NotNullWhen(true)] out DocumentContext? context) - { - throw new NotSupportedException("OOP doesn't support this yet, because we don't have a way to pass in the right solution snapshot to use"); - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index 048058709b3..e7a2232c0a6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -1,6 +1,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -13,12 +14,12 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; internal class RemoteDocumentSnapshot(TextDocument textDocument, RemoteProjectSnapshot projectSnapshot) : IDocumentSnapshot { - // TODO: Delete this field when the source generator is hooked up - private Document? _generatedDocument; - private readonly TextDocument _textDocument = textDocument; private readonly RemoteProjectSnapshot _projectSnapshot = projectSnapshot; + // TODO: Delete this field when the source generator is hooked up + private Document? _generatedDocument; + private RazorCodeDocument? _codeDocument; public TextDocument TextDocument => _textDocument; @@ -46,9 +47,9 @@ public async Task GetGeneratedOutputAsync() // TODO: We don't need to worry about locking if we get called from the didOpen/didChange LSP requests, as CLaSP // takes care of that for us, and blocks requests until those are complete. If that doesn't end up happening, // then a locking mechanism here would prevent concurrent compilations. - if (_codeDocument is not null) + if (TryGetGeneratedOutput(out var codeDocument)) { - return _codeDocument; + return codeDocument; } // The non-cohosted DocumentSnapshot implementation uses DocumentState to get the generated output, and we could do that too @@ -66,15 +67,11 @@ public async Task GetGeneratedOutputAsync() // TODO: Get the configuration for forceRuntimeCodeGeneration // var forceRuntimeCodeGeneration = _projectSnapshot.Configuration.LanguageServerFlags?.ForceRuntimeCodeGeneration ?? false; - _codeDocument = await DocumentState.GenerateCodeDocumentAsync(tagHelpers, projectEngine, this, imports, forceRuntimeCodeGeneration: false).ConfigureAwait(false); + codeDocument = await DocumentState + .GenerateCodeDocumentAsync(this, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration: false) + .ConfigureAwait(false); - return _codeDocument; - } - - public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) - { - result = _codeDocument; - return result is not null; + return InterlockedOperations.Initialize(ref _codeDocument, codeDocument); } public IDocumentSnapshot WithText(SourceText text) @@ -85,43 +82,20 @@ public IDocumentSnapshot WithText(SourceText text) return new RemoteDocumentSnapshot(newDocument, _projectSnapshot); } - public bool TryGetGeneratedDocument([NotNullWhen(true)] out Document? generatedDocument) - { - // TODO: Delete this method when the source generator is hooked up - generatedDocument = _generatedDocument; - return _generatedDocument is not null; - } - - public void SetGeneratedDocument(Document generatedDocument) + public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) { - if (_generatedDocument is not null) - { - ThrowHelper.ThrowInvalidOperationException("A single document snapshot can only ever possibly have a single generated document"); - } - - _generatedDocument = generatedDocument; + result = _codeDocument; + return result is not null; } - /// - /// Sets the generated C# document for this snapshot - /// - /// - /// You're right, dear reader, it's very strange for a seemingly immutable object to have a set method, but we can get away - /// with it here for some arguably tenuous reasons: - /// 1. The generated document is generated from this snapshot, and we're only allowing setting it because it could be - /// expensive to generate in the constructor. - /// 2. This is only temporary until the source generator is properly hooked up. - /// 3. If the Razor document changes, which would invalidate this generated document, then a new document snapshot would - /// be created and this instance would never be used again - /// - internal Document GetOrAddGeneratedDocument(Document generatedDocument) + public async Task GetOrAddGeneratedDocumentAsync(TArg arg, Func> createGeneratedDocument) { - // TODO: Delete this method when the source generator is hooked up - if (_generatedDocument is null) + if (_generatedDocument is Document generatedDocument) { - _generatedDocument = generatedDocument; + return generatedDocument; } - return generatedDocument; + generatedDocument = await createGeneratedDocument(arg); + return InterlockedOperations.Initialize(ref _generatedDocument, generatedDocument); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs index 2676dd1ab5f..cfd8e70171a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -25,22 +25,23 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; internal class RemoteProjectSnapshot : IProjectSnapshot { + public ProjectKey Key { get; } + private readonly Project _project; private readonly DocumentSnapshotFactory _documentSnapshotFactory; private readonly ITelemetryReporter _telemetryReporter; - private readonly ProjectKey _projectKey; private readonly Lazy _lazyConfiguration; private readonly Lazy _lazyProjectEngine; private readonly Lazy>> _importsToRelatedDocumentsLazy; - private ImmutableArray? _tagHelpers; + private ImmutableArray _tagHelpers; public RemoteProjectSnapshot(Project project, DocumentSnapshotFactory documentSnapshotFactory, ITelemetryReporter telemetryReporter) { _project = project; _documentSnapshotFactory = documentSnapshotFactory; _telemetryReporter = telemetryReporter; - _projectKey = _project.ToProjectKey(); + Key = _project.ToProjectKey(); _lazyConfiguration = new Lazy(CreateRazorConfiguration); _lazyProjectEngine = new Lazy(() => @@ -59,24 +60,39 @@ public RemoteProjectSnapshot(Project project, DocumentSnapshotFactory documentSn _importsToRelatedDocumentsLazy = new Lazy>>(() => { var importsToRelatedDocuments = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); - foreach (var document in DocumentFilePaths) + foreach (var documentFilePath in DocumentFilePaths) { - var importTargetPaths = ProjectState.GetImportDocumentTargetPaths(document, FileKinds.GetFileKindFromFilePath(document), _lazyProjectEngine.Value); - importsToRelatedDocuments = ProjectState.AddToImportsToRelatedDocuments(importsToRelatedDocuments, document, importTargetPaths); + var importTargetPaths = ProjectState.GetImportDocumentTargetPaths(documentFilePath, FileKinds.GetFileKindFromFilePath(documentFilePath), _lazyProjectEngine.Value); + importsToRelatedDocuments = ProjectState.AddToImportsToRelatedDocuments(importsToRelatedDocuments, documentFilePath, importTargetPaths); } return importsToRelatedDocuments; }); } - public ProjectKey Key => _projectKey; - public RazorConfiguration Configuration => throw new InvalidOperationException("Should not be called for cohosted projects."); public IEnumerable DocumentFilePaths - => _project.AdditionalDocuments - .Where(d => d.FilePath!.EndsWith(".razor", StringComparison.OrdinalIgnoreCase) || d.FilePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)) - .Select(d => d.FilePath.AssumeNotNull()); + { + get + { + foreach (var additionalDocument in _project.AdditionalDocuments) + { + if (additionalDocument.FilePath is not string filePath) + { + continue; + } + + if (!filePath.EndsWith(".razor", StringComparison.OrdinalIgnoreCase) && + !filePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + yield return filePath; + } + } + } public string FilePath => _project.FilePath!; @@ -92,13 +108,23 @@ public IEnumerable DocumentFilePaths public async ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) { - if (_tagHelpers is null) + if (_tagHelpers.IsDefault) { - var resolver = new CompilationTagHelperResolver(_telemetryReporter); - _tagHelpers = await resolver.GetTagHelpersAsync(_project, _lazyProjectEngine.Value, cancellationToken).ConfigureAwait(false); + var computedTagHelpers = await ComputeTagHelpersAsync(_project, _lazyProjectEngine.Value, _telemetryReporter, cancellationToken); + ImmutableInterlocked.InterlockedInitialize(ref _tagHelpers, computedTagHelpers); } - return _tagHelpers.GetValueOrDefault(); + return _tagHelpers; + + static ValueTask> ComputeTagHelpersAsync( + Project project, + RazorProjectEngine projectEngine, + ITelemetryReporter telemetryReporter, + CancellationToken cancellationToken) + { + var resolver = new CompilationTagHelperResolver(telemetryReporter); + return resolver.GetTagHelpersAsync(project, projectEngine, cancellationToken); + } } public ProjectWorkspaceState ProjectWorkspaceState => throw new InvalidOperationException("Should not be called for cohosted projects."); @@ -134,26 +160,26 @@ public ImmutableArray GetRelatedDocuments(IDocumentSnapshot d if (!_importsToRelatedDocumentsLazy.Value.TryGetValue(targetPath, out var relatedDocuments)) { - return ImmutableArray.Empty; + return []; } - using var _ = ArrayBuilderPool.GetPooledObject(out var builder); - builder.SetCapacityIfLarger(relatedDocuments.Length); + using var builder = new PooledArrayBuilder(relatedDocuments.Length); foreach (var relatedDocumentFilePath in relatedDocuments) { - if (GetDocument(relatedDocumentFilePath) is { } relatedDocument) + if (TryGetDocument(relatedDocumentFilePath, out var relatedDocument)) { builder.Add(relatedDocument); } } - return builder.ToImmutableArray(); + return builder.DrainToImmutable(); } public bool IsImportDocument(IDocumentSnapshot document) { - return document.TargetPath is { } targetPath && _importsToRelatedDocumentsLazy.Value.ContainsKey(targetPath); + return document.TargetPath is { } targetPath && + _importsToRelatedDocumentsLazy.Value.ContainsKey(targetPath); } private RazorConfiguration CreateRazorConfiguration() diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs index f8e3087df91..8daf670d224 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs @@ -15,7 +15,7 @@ internal static class RemoteWorkspaceAccessor /// process that is explicitly denied via an exception. This method serves as a workaround when a workspace is /// needed (eg, the Go To Definition API requires one). /// - /// This should be used sparingly nad carefully, and no updates should be made to the workspace. + /// This should be used sparingly and carefully, and no updates should be made to the workspace. /// public static Workspace GetWorkspace() => RazorBrokeredServiceImplementation.GetWorkspace(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs index 9414fa0ec1f..a9b19f9a2c2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens; [Export(typeof(IRazorSemanticTokensInfoService)), Shared] [method: ImportingConstructor] internal class RazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs index 08971e58191..fb4fa23635a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs @@ -26,7 +26,7 @@ protected override IRemoteSignatureHelpService CreateService(in ServiceArgs args } private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); public ValueTask GetSignatureHelpAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId documentId, Position position, CancellationToken cancellationToken) => RunServiceAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs index db920ccee6c..23336fb656d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs @@ -25,7 +25,7 @@ protected override IRemoteUriPresentationService CreateService(in ServiceArgs ar => new RemoteUriPresentationService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); public ValueTask GetPresentationAsync( RazorPinnedSolutionInfoWrapper solutionInfo, @@ -73,8 +73,7 @@ private async ValueTask GetPresentationAsync( var solution = context.TextDocument.Project.Solution; // Make sure we go through Roslyn to go from the Uri the client sent us, to one that it has a chance of finding in the solution - var uriToFind = RazorUri.GetDocumentFilePathFromUri(razorFileUri); - var ids = solution.GetDocumentIdsWithFilePath(uriToFind); + var ids = solution.GetDocumentIdsWithUri(razorFileUri); if (ids.Length == 0) { return Response.CallHtml; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs index 2196a72ccfa..e9992610258 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs @@ -55,7 +55,7 @@ private GenerateMethodCodeActionResolver[] CreateRazorCodeActionResolvers( new GenerateMethodResolverDocumentContextFactory(filePath, codeDocument), optionsMonitor ?? TestRazorLSPOptionsMonitor.Create(), clientConnection, - new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory), + new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory), razorFormattingService) ]; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs index e5dc42a3fb7..7c44e564389 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs @@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; public class CodeActionEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly IClientConnection _clientConnection; public CodeActionEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _documentMappingService = Mock.Of( + _documentMappingService = Mock.Of( s => s.TryMapToGeneratedDocumentRange( It.IsAny(), It.IsAny(), @@ -688,7 +688,7 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_InvalidRangeMappin var codeDocument = CreateCodeDocument("@code {}"); var documentContext = CreateDocumentContext(documentPath, codeDocument); LinePositionSpan projectedRange = default; - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( d => d.TryMapToGeneratedDocumentRange(It.IsAny(), It.IsAny(), out projectedRange) == false , MockBehavior.Strict); var codeActionEndpoint = new CodeActionEndpoint( @@ -782,14 +782,14 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_ReturnsCodeActions Assert.Equal(projectedRange, diagnostics[1].Range); } - private static IRazorDocumentMappingService CreateDocumentMappingService(LinePositionSpan projectedRange = default) + private static IDocumentMappingService CreateDocumentMappingService(LinePositionSpan projectedRange = default) { if (projectedRange == default) { projectedRange = new LinePositionSpan(new(5, 2), new(5, 2)); } - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( d => d.TryMapToGeneratedDocumentRange(It.IsAny(), It.IsAny(), out projectedRange) == true && d.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp , MockBehavior.Strict); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs index 5104d53b0fa..a02a209f947 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -42,7 +43,7 @@ public async Task ProvideAsync_WrapsResolvableCodeActions() var context = CreateRazorCodeActionContext(request, location, documentPath, contents); context.CodeDocument.SetFileKind(FileKinds.Legacy); - var documentMappingService = Mock.Of(MockBehavior.Strict); + var documentMappingService = StrictMock.Of(); var provider = new DefaultHtmlCodeActionProvider(documentMappingService); ImmutableArray codeActions = [ new RazorVSInternalCodeAction() { Name = "Test" } ]; @@ -90,12 +91,12 @@ public async Task ProvideAsync_RemapsAndFixesEdits() } }; - var documentMappingServiceMock = new Mock(MockBehavior.Strict); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(x => x.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(remappedEdit); - var provider = new DefaultHtmlCodeActionProvider(documentMappingServiceMock.Object); + var provider = new DefaultHtmlCodeActionProvider(editMappingServiceMock.Object); ImmutableArray codeActions = [ diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs index 5d7704aa426..9593a139a17 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs @@ -7,14 +7,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -56,12 +55,12 @@ public async Task ResolveAsync_RemapsAndFixesEdits() Edit = remappedEdit }; - var documentMappingServiceMock = new Mock(MockBehavior.Strict); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(x => x.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(remappedEdit); - var resolver = new DefaultHtmlCodeActionResolver(documentContextFactory, CreateLanguageServer(resolvedCodeAction), documentMappingServiceMock.Object); + var resolver = new DefaultHtmlCodeActionResolver(documentContextFactory, CreateLanguageServer(resolvedCodeAction), editMappingServiceMock.Object); var codeAction = new RazorVSInternalCodeAction() { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs index b39900715b0..90b3f93b7db 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs @@ -52,8 +52,24 @@ public DelegatedCompletionItemResolverTest(ITestOutputHelper testOutput) }; var documentContext = TestDocumentContext.From("C:/path/to/file.cshtml", hostDocumentVersion: 0); - _csharpCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.CreatePosition(10, 6), RazorLanguageKind.CSharp, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); - _htmlCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.DefaultPosition, RazorLanguageKind.Html, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); + _csharpCompletionParams = new DelegatedCompletionParams( + documentContext.GetTextDocumentIdentifierAndVersion(), + VsLspFactory.CreatePosition(10, 6), + RazorLanguageKind.CSharp, + new VSInternalCompletionContext(), + ProvisionalTextEdit: null, + ShouldIncludeSnippets: false, + CorrelationId: Guid.Empty); + + _htmlCompletionParams = new DelegatedCompletionParams( + documentContext.GetTextDocumentIdentifierAndVersion(), + VsLspFactory.DefaultPosition, + RazorLanguageKind.Html, + new VSInternalCompletionContext(), + ProvisionalTextEdit: null, + ShouldIncludeSnippets: false, + CorrelationId: Guid.Empty); + _documentContextFactory = new TestDocumentContextFactory(); _formattingService = new AsyncLazy(() => TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory)); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs index bb8dee4338e..746ba8cc729 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs @@ -26,7 +26,7 @@ private TestDelegatedCompletionListProvider( ILoggerFactory loggerFactory) : base( responseRewriters, - new RazorDocumentMappingService(new LSPFilePathService(TestLanguageServerFeatureOptions.Instance), new TestDocumentContextFactory(), loggerFactory), + new LspDocumentMappingService(new LSPFilePathService(TestLanguageServerFeatureOptions.Instance), new TestDocumentContextFactory(), loggerFactory), new TestLanguageServer(new Dictionary>>() { [LanguageServerConstants.RazorCompletionEndpointName] = completionFactory.OnDelegationAsync, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs index a684d4632e8..7a2dbb635fc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs @@ -248,14 +248,17 @@ public TagHelperServiceTestBase(ITestOutputHelper testOutput) RazorTagHelperCompletionService = new LspTagHelperCompletionService(); } + protected static string GetFileName(bool isRazorFile) + => isRazorFile ? RazorFile : CSHtmlFile; + internal static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, ImmutableArray tagHelpers) { - return CreateCodeDocument(text, isRazorFile ? RazorFile : CSHtmlFile, tagHelpers); + return CreateCodeDocument(text, GetFileName(isRazorFile), tagHelpers); } internal static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params TagHelperDescriptor[] tagHelpers) { - return CreateCodeDocument(text, isRazorFile ? RazorFile : CSHtmlFile, tagHelpers); + return CreateCodeDocument(text, GetFileName(isRazorFile), tagHelpers); } internal static RazorCodeDocument CreateCodeDocument(string text, string filePath, ImmutableArray tagHelpers) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs index 4d19dee877a..874158e576e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs @@ -9,11 +9,10 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; -internal class TestDocumentMappingService : IRazorDocumentMappingService +internal class TestDocumentMappingService : IDocumentMappingService { public RazorLanguageKind LanguageKind { get; set; } public LinePosition? GeneratedPosition { get; set; } @@ -30,11 +29,6 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos throw new NotImplementedException(); } - public Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - public bool TryMapToGeneratedDocumentOrNextCSharpPosition(IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, out LinePosition generatedPosition, out int generatedIndex) { throw new NotImplementedException(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs index bfae068bda8..718cbcfc0d5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs @@ -15,12 +15,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; public class RazorBreakpointSpanEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _mappingService; public RazorBreakpointSpanEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _mappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs index e8bfb086782..66f45a89fc0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs @@ -15,12 +15,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; public class RazorProximityExpressionsEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _mappingService; public RazorProximityExpressionsEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _mappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs index ebfb6b65708..02ae91c9c9b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs @@ -395,7 +395,7 @@ private async Task VerifyNavigatePositionAsync(string content, string propertyNa SetupDocument(out var codeDocument, out _, content); var expectedRange = codeDocument.Source.Text.GetRange(selection); - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var range = await DefinitionEndpoint.TryGetPropertyRangeAsync(codeDocument, propertyName, mappingService, Logger, DisposalToken); Assert.NotNull(range); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs index b5d4b12c60a..ecbadccdd23 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs @@ -18,7 +18,7 @@ public sealed class DocumentPullDiagnosticsEndpointTest(ITestOutputHelper testOu public void ApplyCapabilities_AddsExpectedCapabilities() { // Arrange - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var razorTranslate = new Mock(MockBehavior.Strict, documentMappingService, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index e5910df49ec..4cdbc79137d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -111,7 +111,7 @@ public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() .Verifiable(); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -218,7 +218,7 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new RazorDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); @@ -275,7 +275,7 @@ public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -333,7 +333,7 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -370,7 +370,7 @@ public async Task PublishDiagnosticsAsync_NoopsIfRazorDiagnosticsAreSameAsPrevio var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new RazorDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); @@ -422,7 +422,7 @@ public async Task PublishDiagnosticsAsync_NoopsIfCSharpDiagnosticsAreSameAsPrevi .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -453,7 +453,7 @@ public void ClearClosedDocuments_ClearsDiagnosticsForClosedDocument() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -473,7 +473,7 @@ public void ClearClosedDocuments_NoopsIfDocumentIsStillOpen() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -490,7 +490,7 @@ public void ClearClosedDocuments_NoopsIfDocumentIsClosedButNoDiagnostics() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -507,7 +507,7 @@ public void ClearClosedDocuments_RestartsTimerIfDocumentsStillOpen() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs index 59b5b074499..060c282439d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs @@ -121,7 +121,7 @@ private async Task VerifyHighlightingRangesAsync(string input) MockBehavior.Strict); var languageServer = new DocumentHighlightServer(csharpServer, csharpDocumentUri); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var endpoint = new DocumentHighlightEndpoint( languageServerFeatureOptions, documentMappingService, languageServer, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs index f5af246e6e4..7c36bf571c9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs @@ -25,7 +25,7 @@ public async Task Handle_Html_MakesRequest() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var uri = new Uri("file://path/test.razor"); @@ -72,7 +72,7 @@ public async Task Handle_CSharp_DoesNotMakeRequest() var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); var projectedRange = It.IsAny(); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp && s.TryMapToGeneratedDocumentRange(csharpDocument, It.IsAny(), out projectedRange) == true, MockBehavior.Strict); @@ -109,7 +109,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var response = (WorkspaceEdit?)null; @@ -151,7 +151,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() codeDocument.SetUnsupported(); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var response = new WorkspaceEdit(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs index 3e0c2fecef4..318436e546a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs @@ -34,7 +34,7 @@ public async Task Handle_SimpleComponent_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/MyTagHelper.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -92,7 +92,7 @@ public async Task Handle_SimpleComponentWithChildFile_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/MyTagHelper.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -155,7 +155,7 @@ public async Task Handle_ComponentWithRequiredAttribute_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/fetchdata.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/fetchdata.razor"); @@ -214,7 +214,7 @@ public async Task Handle_NoTypeNameIdentifier_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var componentCodeDocument = TestRazorCodeDocument.Create("
"); @@ -265,7 +265,7 @@ public async Task Handle_MultipleUris_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -316,7 +316,7 @@ public async Task Handle_NotComponent_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -368,7 +368,7 @@ public async Task Handle_ComponentWithNestedFiles_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/fetchdata.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri1 = new Uri("file:///c:/path/fetchdata.razor.cs"); @@ -426,7 +426,7 @@ public async Task Handle_CSharp_ReturnsNull() var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); var projectedRange = It.IsAny(); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp && s.TryMapToGeneratedDocumentRange(csharpDocument, It.IsAny(), out projectedRange) == true, MockBehavior.Strict); @@ -471,7 +471,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -516,7 +516,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() codeDocument.SetUnsupported(); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -560,7 +560,7 @@ public async Task Handle_NoUris_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs index 0ba0f51c73c..17177a8e49c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs @@ -24,7 +24,7 @@ public async Task Handle_OnTypeFormatting_FormattingDisabled_ReturnsNull() // Arrange var uri = new Uri("file://path/test.razor"); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: false); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -53,7 +53,7 @@ public async Task Handle_OnTypeFormatting_DocumentNotFound_ReturnsNull() var documentContext = CreateDocumentContext(new Uri("file://path/testDifferentFile.razor"), codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -88,7 +88,7 @@ public async Task Handle_OnTypeFormatting_RemapFailed_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -124,7 +124,7 @@ public async Task Handle_OnTypeFormatting_HtmlLanguageKind_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new Mock(MockBehavior.Strict); + var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Html); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -160,7 +160,7 @@ public async Task Handle_OnTypeFormatting_RazorLanguageKind_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new Mock(MockBehavior.Strict); + var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Razor); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -195,7 +195,7 @@ public async Task Handle_OnTypeFormatting_UnexpectedTriggerCharacter_ReturnsNull var documentContextFactory = CreateDocumentContextFactory(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs index 4e9160ab8b6..d42f0778dc8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs @@ -110,7 +110,7 @@ public class Foo { } private FormattingContentValidationPass GetPass() { - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var pass = new FormattingContentValidationPass(mappingService, LoggerFactory) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs index ed17457db2a..c0f06e9831e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs @@ -107,7 +107,7 @@ public class Foo { } private FormattingDiagnosticValidationPass GetPass() { - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var pass = new FormattingDiagnosticValidationPass(mappingService, LoggerFactory) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 9ec26d51add..112e7ae0016 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -116,7 +116,7 @@ private protected async Task RunOnTypeFormattingTestAsync( var (codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind, inGlobalNamespace: inGlobalNamespace); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService( + var mappingService = new LspDocumentMappingService( filePathService, new TestDocumentContextFactory(), LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger, rightAssociative: false); @@ -177,7 +177,7 @@ protected async Task RunCodeActionFormattingTestAsync( var (codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind, inGlobalNamespace: inGlobalNamespace); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService(filePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(filePathService, new TestDocumentContextFactory(), LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger, rightAssociative: false); if (languageKind == RazorLanguageKind.Html) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs index 9a32d0ce57d..12c22645152 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs @@ -27,7 +27,7 @@ public static async Task CreateWithFullSupportAsync( codeDocument ??= TestRazorCodeDocument.CreateEmpty(); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService(filePathService, new TestDocumentContextFactory(), loggerFactory); + var mappingService = new LspDocumentMappingService(filePathService, new TestDocumentContextFactory(), loggerFactory); var projectManager = StrictMock.Of(); var versionCache = new DocumentVersionCache(projectManager); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs index 335945678d6..d7a1c2bc4a2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs @@ -725,7 +725,7 @@ public async Task Handle_Hover_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.SendRequestAsync(CustomMessageNames.RazorHoverEndpointName, It.IsAny(), It.IsAny())) .ReturnsAsync(delegatedHover); - var documentMappingServiceMock = new Mock(MockBehavior.Strict); + var documentMappingServiceMock = new Mock(MockBehavior.Strict); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.CSharp); @@ -880,7 +880,7 @@ private async Task GetResultFromSingleServerEndpointAsync(strin options.UseRazorCohostServer == false , MockBehavior.Strict); var languageServer = new HoverLanguageServer(csharpServer, csharpDocumentUri, DisposalToken); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var service = GetHoverService(documentMappingService); @@ -936,12 +936,12 @@ public void Increment(){ private HoverEndpoint CreateEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions = null, - IRazorDocumentMappingService documentMappingService = null, + IDocumentMappingService documentMappingService = null, IClientConnection clientConnection = null) { languageServerFeatureOptions ??= Mock.Of(options => options.SupportsFileManipulation == true && options.SingleServerSupport == false, MockBehavior.Strict); - var documentMappingServiceMock = new Mock(MockBehavior.Strict); + var documentMappingServiceMock = new Mock(MockBehavior.Strict); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Html); @@ -961,7 +961,7 @@ private HoverEndpoint CreateEndpoint( return endpoint; } - private HoverService GetHoverService(IRazorDocumentMappingService mappingService = null) + private HoverService GetHoverService(IDocumentMappingService mappingService = null) { var projectManager = CreateProjectSnapshotManager(); var lspTagHelperTooltipFactory = new DefaultLSPTagHelperTooltipFactory(projectManager); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs index ba8a4a7fce8..22d3bf89399 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs @@ -290,7 +290,7 @@ private async Task VerifyCodeMappingAsync( var documentContextFactory = new TestDocumentContextFactory(razorFilePath, codeDocument, version: 1337); var languageServer = new MapCodeServer(csharpServer, csharpDocumentUri); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var endpoint = new MapCodeEndpoint(documentMappingService, documentContextFactory, languageServer, NoOpTelemetryReporter.Instance); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs index 7f056bbde56..4d52de66276 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs @@ -19,12 +19,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Mapping; public class RazorLanguageQueryEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _documentMappingService; public RazorLanguageQueryEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _documentMappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); @@ -37,7 +37,7 @@ public async Task Handle_ResolvesLanguageRequest_Razor() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("@{}"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorLanguageQueryEndpoint(_mappingService, LoggerFactory); + var languageEndpoint = new RazorLanguageQueryEndpoint(_documentMappingService, LoggerFactory); var request = new RazorLanguageQueryParams() { Uri = documentPath, @@ -64,7 +64,7 @@ public async Task Handle_ResolvesLanguageRequest_Html() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("@DateTime.Now

"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Html, @@ -196,7 +196,7 @@ public async Task Handle_MapToDocumentRanges_Razor() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("

@DateTime.Now

"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Razor, @@ -230,7 +230,7 @@ public async Task Handle_MapToDocumentRanges_Unsupported() ]); codeDocument.SetUnsupported(); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs index 511b5a2ae2f..8bd5c180295 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs @@ -35,7 +35,7 @@ public RazorDocumentMappingServiceTest(ITestOutputHelper testOutput) public void TryMapToHostDocumentRange_Strict_StartOnlyMaps_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -58,7 +58,7 @@ public void TryMapToHostDocumentRange_Strict_StartOnlyMaps_ReturnsFalse() public void TryMapToHostDocumentRange_Strict_EndOnlyMaps_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -81,7 +81,7 @@ public void TryMapToHostDocumentRange_Strict_EndOnlyMaps_ReturnsFalse() public void TryMapToHostDocumentRange_Strict_StartAndEndMap_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -105,7 +105,7 @@ public void TryMapToHostDocumentRange_Strict_StartAndEndMap_ReturnsTrue() public void TryMapToHostDocumentRange_Inclusive_DirectlyMaps_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -129,7 +129,7 @@ public void TryMapToHostDocumentRange_Inclusive_DirectlyMaps_ReturnsTrue() public void TryMapToHostDocumentRange_Inclusive_StartSinglyIntersects_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -153,7 +153,7 @@ public void TryMapToHostDocumentRange_Inclusive_StartSinglyIntersects_ReturnsTru public void TryMapToHostDocumentRange_Inclusive_EndSinglyIntersects_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -177,7 +177,7 @@ public void TryMapToHostDocumentRange_Inclusive_EndSinglyIntersects_ReturnsTrue( public void TryMapToHostDocumentRange_Inclusive_StartDoublyIntersects_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -204,7 +204,7 @@ public void TryMapToHostDocumentRange_Inclusive_StartDoublyIntersects_ReturnsFal public void TryMapToHostDocumentRange_Inclusive_EndDoublyIntersects_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -231,7 +231,7 @@ public void TryMapToHostDocumentRange_Inclusive_EndDoublyIntersects_ReturnsFalse public void TryMapToHostDocumentRange_Inclusive_OverlapsSingleMapping_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -255,7 +255,7 @@ public void TryMapToHostDocumentRange_Inclusive_OverlapsSingleMapping_ReturnsTru public void TryMapToHostDocumentRange_Inclusive_OverlapsTwoMappings_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -282,7 +282,7 @@ public void TryMapToHostDocumentRange_Inclusive_OverlapsTwoMappings_ReturnsFalse public void TryMapToHostDocumentRange_Inferred_DirectlyMaps_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -306,7 +306,7 @@ public void TryMapToHostDocumentRange_Inferred_DirectlyMaps_ReturnsTrue() public void TryMapToHostDocumentRange_Inferred_BeginningOfDocAndProjection_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@

@DateTime.Now

", "(__builder) => { };__o = DateTime.Now;", @@ -329,7 +329,7 @@ public void TryMapToHostDocumentRange_Inferred_BeginningOfDocAndProjection_Retur public void TryMapToHostDocumentRange_Inferred_InbetweenProjections_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @ }", " var abc = (__builder) => { } ", @@ -356,7 +356,7 @@ public void TryMapToHostDocumentRange_Inferred_InbetweenProjections_ReturnsTrue( public void TryMapToHostDocumentRange_Inferred_InbetweenProjectionAndEndOfDoc_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -380,7 +380,7 @@ public void TryMapToHostDocumentRange_Inferred_InbetweenProjectionAndEndOfDoc_Re public void TryMapToHostDocumentRange_Inferred_OutsideDoc_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -416,7 +416,7 @@ public void TryMapToHostDocumentRange_Inferred_OutOfOrderMappings_DoesntThrow() // that has some very strange mappings! // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -443,7 +443,7 @@ public void TryMapToHostDocumentRange_Inferred_OutOfOrderMappings_DoesntThrow() public void TryMapToGeneratedDocumentPosition_NotMatchingAnyMapping() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "test razor source", "test C# source", @@ -466,7 +466,7 @@ public void TryMapToGeneratedDocumentPosition_NotMatchingAnyMapping() public void TryMapToGeneratedDocumentPosition_CSharp_OnLeadingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -496,7 +496,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_OnLeadingEdge() public void TryMapToGeneratedDocumentPosition_CSharp_InMiddle() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -526,7 +526,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_InMiddle() public void TryMapToGeneratedDocumentPosition_CSharp_OnTrailingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -556,7 +556,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_OnTrailingEdge() public void TryMapToHostDocumentPosition_NotMatchingAnyMapping() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "test razor source", projectedCSharpSource: "projectedCSharpSource: test C# source", @@ -579,7 +579,7 @@ public void TryMapToHostDocumentPosition_NotMatchingAnyMapping() public void TryMapToHostDocumentPosition_CSharp_OnLeadingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -609,7 +609,7 @@ public void TryMapToHostDocumentPosition_CSharp_OnLeadingEdge() public void TryMapToHostDocumentPosition_CSharp_InMiddle() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -639,7 +639,7 @@ public void TryMapToHostDocumentPosition_CSharp_InMiddle() public void TryMapToHostDocumentPosition_CSharp_OnTrailingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -669,7 +669,7 @@ public void TryMapToHostDocumentPosition_CSharp_OnTrailingEdge() public void TryMapToGeneratedDocumentRange_CSharp() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -700,7 +700,7 @@ public void TryMapToGeneratedDocumentRange_CSharp() public void TryMapToGeneratedDocumentRange_CSharp_MissingSourceMappings() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -724,7 +724,7 @@ public void TryMapToGeneratedDocumentRange_CSharp_MissingSourceMappings() public void TryMapToGeneratedDocumentRange_CSharp_End_LessThan_Start() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -760,7 +760,7 @@ public void GetLanguageKindCore_TagHelperElementOwnsName() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 32 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 32 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -780,7 +780,7 @@ public void GetLanguageKindCore_TagHelpersDoNotOwnTrailingEdge() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 42 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 42 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Razor, languageKind); @@ -806,7 +806,7 @@ public void GetLanguageKindCore_TagHelperNestedCSharpAttribute() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 46 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 46 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -820,7 +820,7 @@ public void GetLanguageKindCore_CSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -834,7 +834,7 @@ public void GetLanguageKindCore_Html() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -848,7 +848,7 @@ public void GetLanguageKindCore_DefaultsToRazorLanguageIfCannotLocateOwner() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length + 1, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length + 1, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Razor, languageKind); @@ -876,7 +876,7 @@ public void GetLanguageKindCore_GetsLastClassifiedSpanLanguageIfAtEndOfDocument( var tagHelperSpans = ImmutableArray.Empty; // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -890,7 +890,7 @@ public void GetLanguageKindCore_HtmlEdgeEnd() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -904,7 +904,7 @@ public void GetLanguageKindCore_CSharpEdgeEnd() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -918,7 +918,7 @@ public void GetLanguageKindCore_RazorEdgeWithCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -932,7 +932,7 @@ public void GetLanguageKindCore_CSharpEdgeWithCSharpMarker() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 12, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 12, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -946,7 +946,7 @@ public void GetLanguageKindCore_ExplicitExpressionStartCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -960,7 +960,7 @@ public void GetLanguageKindCore_ExplicitExpressionInProgressCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 4, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 4, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -974,7 +974,7 @@ public void GetLanguageKindCore_ImplicitExpressionStartCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 1, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 1, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -988,7 +988,7 @@ public void GetLanguageKindCore_ImplicitExpressionInProgressCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 3, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 3, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -1002,7 +1002,7 @@ public void GetLanguageKindCore_RazorEdgeWithHtml() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -1016,7 +1016,7 @@ public void GetLanguageKindCore_HtmlInCSharpLeftAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -1030,7 +1030,7 @@ public void GetLanguageKindCore_HtmlInCSharpRightAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act\ - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: true); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: true); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -1052,7 +1052,7 @@ public void GetLanguageKindCore_TagHelperInCSharpRightAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act\ - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 40, text.Length, rightAssociative: true); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 40, text.Length, rightAssociative: true); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs index b4f067970fb..4188b6bc72b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs @@ -71,6 +71,7 @@ await projectManager.UpdateAsync(updater => projectManager, LanguageServerFeatureOptions, DocumentMappingService, + EditMappingService, languageServer, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index bde6e054c50..c812fcdbaae 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -526,13 +526,10 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.SendRequestAsync(CustomMessageNames.RazorRenameEndpointName, It.IsAny(), It.IsAny())) .ReturnsAsync(delegatedEdit); - var documentMappingServiceMock = new StrictMock(); + var documentMappingServiceMock = new StrictMock(); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.CSharp); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(delegatedEdit); var projectedPosition = new LinePosition(1, 1); var projectedIndex = 1; @@ -540,7 +537,16 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) .Returns(true); - var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync(options, documentMappingServiceMock.Object, clientConnectionMock.Object); + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(delegatedEdit); + + var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync( + options, + documentMappingServiceMock.Object, + editMappingServiceMock.Object, + clientConnectionMock.Object); var uri = PathUtilities.GetUri(s_componentWithParamFilePath); var request = new RenameParams @@ -570,12 +576,18 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() o.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false); var clientConnection = StrictMock.Of(); - var documentMappingServiceMock = new StrictMock(); + var documentMappingServiceMock = new StrictMock(); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Razor); - var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync(options, documentMappingServiceMock.Object, clientConnection); + var editMappingService = StrictMock.Of(); + + var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync( + options, + documentMappingServiceMock.Object, + editMappingService, + clientConnection); var request = new RenameParams { @@ -596,7 +608,8 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() private async Task<(RenameEndpoint, IDocumentContextFactory)> CreateEndpointAndDocumentContextFactoryAsync( LanguageServerFeatureOptions? options = null, - IRazorDocumentMappingService? documentMappingService = null, + IDocumentMappingService? documentMappingService = null, + IEditMappingService? editMappingService = null, IClientConnection? clientConnection = null) { using PooledArrayBuilder builder = []; @@ -677,16 +690,21 @@ await projectManager.UpdateAsync(updater => o.SingleServerSupport == false && o.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false); - var documentMappingServiceMock = new StrictMock(); - documentMappingServiceMock - .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(RazorLanguageKind.Html); - var projectedPosition = new LinePosition(1, 1); - var projectedIndex = 1; - documentMappingServiceMock - .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) - .Returns(true); - documentMappingService ??= documentMappingServiceMock.Object; + if (documentMappingService == null) + { + var documentMappingServiceMock = new StrictMock(); + documentMappingServiceMock + .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(RazorLanguageKind.Html); + var projectedPosition = new LinePosition(1, 1); + var projectedIndex = 1; + documentMappingServiceMock + .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) + .Returns(true); + documentMappingService = documentMappingServiceMock.Object; + } + + editMappingService ??= StrictMock.Of(); clientConnection ??= StrictMock.Of(); @@ -695,6 +713,7 @@ await projectManager.UpdateAsync(updater => projectManager, options, documentMappingService, + editMappingService, clientConnection, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 4c460d0cffd..0bcf1c28d4e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -923,34 +923,31 @@ private static VersionedDocumentContext CreateDocumentContext( string documentText, bool isRazorFile, ImmutableArray tagHelpers, - int? documentVersion) + int version) { var document = CreateCodeDocument(documentText, isRazorFile, tagHelpers); - var random = new Random(); - var projectSnapshot = new Mock(MockBehavior.Strict); + var projectSnapshot = new StrictMock(); projectSnapshot - .Setup(p => p.Version) - .Returns(default(VersionStamp)); + .SetupGet(p => p.Version) + .Returns(VersionStamp.Default); - var documentSnapshot = Mock.Of(MockBehavior.Strict); - var documentContext = new Mock(MockBehavior.Strict, new Uri("c:/path/to/file.razor"), documentSnapshot, /* projectContext */ null, 0); - documentContext.Setup(d => d.GetCodeDocumentAsync(It.IsAny())) - .ReturnsAsync(document); - - documentContext.SetupGet(d => d.Version) - .Returns(documentVersion ?? random.Next()); - - documentContext.Setup(d => d.Project) + var documentSnapshotMock = new StrictMock(); + documentSnapshotMock + .SetupGet(x => x.Project) .Returns(projectSnapshot.Object); + documentSnapshotMock + .Setup(x => x.GetGeneratedOutputAsync()) + .ReturnsAsync(document); + documentSnapshotMock + .Setup(x => x.GetTextAsync()) + .ReturnsAsync(document.Source.Text); - documentContext.Setup(d => d.GetSourceTextAsync(It.IsAny())) - .Returns(Task.FromResult(document.Source.Text)); - - documentContext.Setup(d => d.Uri) - .Returns(new Uri($"c:\\${(isRazorFile ? RazorFile : CSHtmlFile)}")); - - return documentContext.Object; + return new VersionedDocumentContext( + uri: new Uri($@"c:\${GetFileName(isRazorFile)}"), + snapshot: documentSnapshotMock.Object, + projectContext: null, + version); } private async Task CreateServiceAsync( @@ -977,7 +974,7 @@ private async Task CreateServiceAsync( : It.Is(x => x.Tokens == null)); var documentContextFactory = new TestDocumentContextFactory(documentSnapshot); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var configurationSyncService = new Mock(MockBehavior.Strict); @@ -1113,7 +1110,7 @@ private string GetBaselineFileContents(string baselineFileName) private ImmutableArray? GetMappedCSharpRanges(RazorCodeDocument codeDocument, LinePositionSpan razorRange, bool precise) { - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); if (precise) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs index 6d5d6cca9a2..853c036a485 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs @@ -24,9 +24,10 @@ public abstract partial class SingleServerDelegatingEndpointTestBase(ITestOutput { private protected IDocumentContextFactory? DocumentContextFactory { get; private set; } private protected LanguageServerFeatureOptions? LanguageServerFeatureOptions { get; private set; } - private protected IRazorDocumentMappingService? DocumentMappingService { get; private set; } + private protected IDocumentMappingService? DocumentMappingService { get; private set; } + private protected IEditMappingService? EditMappingService { get; private set; } - [MemberNotNull(nameof(DocumentContextFactory), nameof(LanguageServerFeatureOptions), nameof(DocumentMappingService))] + [MemberNotNull(nameof(DocumentContextFactory), nameof(LanguageServerFeatureOptions), nameof(DocumentMappingService), nameof(EditMappingService))] private protected async Task CreateLanguageServerAsync( RazorCodeDocument codeDocument, string razorFilePath, @@ -64,7 +65,8 @@ private protected async Task CreateLanguageServerAsync( options.HtmlVirtualDocumentSuffix == DefaultLanguageServerFeatureOptions.DefaultHtmlVirtualDocumentSuffix, MockBehavior.Strict); - DocumentMappingService = new RazorDocumentMappingService(FilePathService, DocumentContextFactory, LoggerFactory); + DocumentMappingService = new LspDocumentMappingService(FilePathService, DocumentContextFactory, LoggerFactory); + EditMappingService = new EditMappingService(DocumentMappingService, FilePathService, DocumentContextFactory); var csharpServer = await CSharpTestLspServerHelpers.CreateCSharpLspServerAsync( csharpFiles, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs index fc85888a50b..80a563b38d4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs @@ -35,7 +35,7 @@ public async Task Handle_Html_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -70,7 +70,7 @@ public async Task Handle_CSharp_ReturnsNull() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -105,7 +105,7 @@ public async Task Handle_CSharp_WholeImplicitStatement_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -140,7 +140,7 @@ public async Task Handle_CSharp_PartOfImplicitStatement_ReturnsNull() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -175,7 +175,7 @@ public async Task Handle_CSharp_InImplicitStatement_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -206,7 +206,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var clientConnection = new Mock(MockBehavior.Strict); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint(clientConnection.Object, documentMappingService, LoggerFactory); @@ -234,7 +234,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() var clientConnection = new Mock(MockBehavior.Strict); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint(clientConnection.Object, documentMappingService, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs index ddae8ddf089..ecf351fe1e8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Composition; @@ -150,9 +151,7 @@ private static AdhocWorkspace CreateCSharpTestWorkspace( var documentCount = 0; foreach (var (documentUri, csharpSourceText) in files) { - // File path logic here has to match https://github.com/dotnet/roslyn/blob/3db75baf44332efd490bc0d166983103552370a3/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs#L163 - // or the Roslyn side won't see the file in the project/solution - var documentFilePath = documentUri.IsFile ? documentUri.LocalPath : documentUri.AbsolutePath; + var documentFilePath = documentUri.GetDocumentFilePath(); var textAndVersion = TextAndVersion.Create(csharpSourceText, VersionStamp.Default, documentFilePath); foreach (var projectInfo in projectInfos) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs index c71e952f94c..062f31cbf03 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs @@ -13,7 +13,7 @@ public StrictMock() { } - public StrictMock(params object[] args) + public StrictMock(params object?[] args) : base(MockBehavior.Strict, args) { }