Create a remote rename service, and dependencies, to perform the rename

This commit is contained in:
David Wengier 2024-08-07 14:40:36 +10:00
Родитель f3881562f7
Коммит 47665e0d26
6 изменённых файлов: 131 добавлений и 0 удалений

Просмотреть файл

@ -25,5 +25,6 @@
<ServiceHubService Include="Microsoft.VisualStudio.Razor.SignatureHelp" ClassName="Microsoft.CodeAnalysis.Remote.Razor.RemoteSignatureHelpService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.Razor.DocumentHighlight" ClassName="Microsoft.CodeAnalysis.Remote.Razor.RemoteDocumentHighlightService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.Razor.InlayHint" ClassName="Microsoft.CodeAnalysis.Remote.Razor.RemoteInlayHintService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.Razor.Rename" ClassName="Microsoft.CodeAnalysis.Remote.Razor.RemoteRenameService+Factory" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.Razor.Remote;
internal interface IRemoteRenameService : IRemoteJsonService
{
ValueTask<RemoteResponse<WorkspaceEdit?>> GetRenameEditAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId documentId, Position position, string newName, CancellationToken cancellationToken);
}

Просмотреть файл

@ -28,6 +28,7 @@ internal static class RazorServices
[
(typeof(IRemoteSignatureHelpService), null),
(typeof(IRemoteInlayHintService), null),
(typeof(IRemoteRenameService), null),
];
private const string ComponentName = "Razor";

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Remote.Razor;
[Export(typeof(IRazorComponentSearchEngine)), Shared]
[method: ImportingConstructor]
internal sealed class RemoteRazorComponentSearchEngine(
IProjectCollectionResolver projectCollectionResolver,
ILoggerFactory loggerFactory) : RazorComponentSearchEngine(projectCollectionResolver, loggerFactory)
{
}

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Razor.Rename;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Remote.Razor.Rename;
[Export(typeof(IRenameService)), Shared]
[method: ImportingConstructor]
internal sealed class OOPRenameService(
IRazorComponentSearchEngine componentSearchEngine,
IProjectCollectionResolver projectCollectionResolver,
LanguageServerFeatureOptions languageServerFeatureOptions) : RenameService(componentSearchEngine, projectCollectionResolver, languageServerFeatureOptions)
{
}

Просмотреть файл

@ -0,0 +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.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Razor.DocumentMapping;
using Microsoft.CodeAnalysis.Razor.Remote;
using Microsoft.CodeAnalysis.Razor.Rename;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using ExternalHandlers = Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers;
using static Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.VisualStudio.LanguageServer.Protocol.WorkspaceEdit?>;
namespace Microsoft.CodeAnalysis.Remote.Razor;
internal sealed class RemoteRenameService(in ServiceArgs args) : RazorDocumentServiceBase(in args), IRemoteRenameService
{
internal sealed class Factory : FactoryBase<IRemoteRenameService>
{
protected override IRemoteRenameService CreateService(in ServiceArgs args)
=> new RemoteRenameService(in args);
}
private readonly IRenameService _renameService = args.ExportProvider.GetExportedValue<IRenameService>();
private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue<IFilePathService>();
private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue<IRazorDocumentMappingService>();
public ValueTask<RemoteResponse<WorkspaceEdit?>> GetRenameEditAsync(
JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo,
JsonSerializableDocumentId documentId,
Position position,
string newName,
CancellationToken cancellationToken)
=> RunServiceAsync(
solutionInfo,
documentId,
context => GetRenameEditAsync(context, position, newName, cancellationToken),
cancellationToken);
private async ValueTask<RemoteResponse<WorkspaceEdit?>> GetRenameEditAsync(
RemoteDocumentContext context,
Position position,
string newName,
CancellationToken cancellationToken)
{
var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false);
var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false);
var hostDocumentIndex = codeDocument.Source.Text.GetRequiredAbsoluteIndex(position);
var positionInfo = _documentMappingService.GetPositionInfo(codeDocument, codeDocument.Source.Text, hostDocumentIndex);
var razorEdit = await _renameService.TryGetRazorRenameEditsAsync(context, positionInfo, newName, cancellationToken).ConfigureAwait(false);
if (razorEdit is not null)
{
return Results(razorEdit);
}
if (positionInfo.LanguageKind != CodeAnalysis.Razor.Protocol.RazorLanguageKind.CSharp)
{
return CallHtml;
}
var csharpEdit = await ExternalHandlers.Rename.GetRenameEditAsync(generatedDocument, positionInfo.Position.ToLinePosition(), newName, cancellationToken).ConfigureAwait(false);
if (csharpEdit is null)
{
return NoFurtherHandling;
}
// This is, to say the least, not ideal. In future we're going to normalize on to Roslyn LSP types, and this can go.
var vsEdit = JsonSerializer.Deserialize<WorkspaceEdit>(JsonSerializer.SerializeToDocument(csharpEdit));
if (vsEdit is null)
{
return NoFurtherHandling;
}
var mappedEdit = await _documentMappingService.RemapWorkspaceEditAsync(vsEdit, cancellationToken).ConfigureAwait(false);
return Results(mappedEdit);
}
}