зеркало из https://github.com/dotnet/razor.git
[VS Code] Fix code action and rename file paths (#8129)
This commit is contained in:
Родитель
2f4f299d9e
Коммит
9880902719
|
@ -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.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
|
||||
|
@ -21,4 +22,9 @@ internal class DefaultLanguageServerFeatureOptions : LanguageServerFeatureOption
|
|||
public override bool SingleServerSupport => false;
|
||||
|
||||
public override bool SupportsDelegatedCodeActions => false;
|
||||
|
||||
// Code action and rename paths in Windows VS Code need to be prefixed with '/':
|
||||
// https://github.com/dotnet/razor/issues/8131
|
||||
public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash
|
||||
=> RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Razor.Language.Syntax;
|
|||
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common.Extensions;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
@ -20,10 +21,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
|
|||
internal class CreateComponentCodeActionResolver : RazorCodeActionResolver
|
||||
{
|
||||
private readonly DocumentContextFactory _documentContextFactory;
|
||||
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
|
||||
|
||||
public CreateComponentCodeActionResolver(DocumentContextFactory documentContextFactory)
|
||||
public CreateComponentCodeActionResolver(DocumentContextFactory documentContextFactory, LanguageServerFeatureOptions languageServerFeatureOptions)
|
||||
{
|
||||
_documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory));
|
||||
_languageServerFeatureOptions = languageServerFeatureOptions ?? throw new ArgumentException(nameof(languageServerFeatureOptions));
|
||||
}
|
||||
|
||||
public override string Action => LanguageServerConstants.CodeActions.CreateComponentFromTag;
|
||||
|
@ -58,10 +61,14 @@ internal class CreateComponentCodeActionResolver : RazorCodeActionResolver
|
|||
return null;
|
||||
}
|
||||
|
||||
// VS Code in Windows expects path to start with '/'
|
||||
var updatedPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !actionParams.Path.StartsWith("/")
|
||||
? '/' + actionParams.Path
|
||||
: actionParams.Path;
|
||||
var newComponentUri = new UriBuilder()
|
||||
{
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
Path = actionParams.Path,
|
||||
Path = updatedPath,
|
||||
Host = string.Empty,
|
||||
}.Uri;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis;
|
|||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using CSharpSyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
|
@ -28,10 +29,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
|
|||
internal class ExtractToCodeBehindCodeActionResolver : RazorCodeActionResolver
|
||||
{
|
||||
private readonly DocumentContextFactory _documentContextFactory;
|
||||
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
|
||||
|
||||
public ExtractToCodeBehindCodeActionResolver(DocumentContextFactory documentContextFactory)
|
||||
public ExtractToCodeBehindCodeActionResolver(
|
||||
DocumentContextFactory documentContextFactory,
|
||||
LanguageServerFeatureOptions languageServerFeatureOptions)
|
||||
{
|
||||
_documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory));
|
||||
_languageServerFeatureOptions = languageServerFeatureOptions;
|
||||
}
|
||||
|
||||
public override string Action => LanguageServerConstants.CodeActions.ExtractToCodeBehindAction;
|
||||
|
@ -69,10 +74,16 @@ internal class ExtractToCodeBehindCodeActionResolver : RazorCodeActionResolver
|
|||
}
|
||||
|
||||
var codeBehindPath = GenerateCodeBehindPath(path);
|
||||
|
||||
// VS Code in Windows expects path to start with '/'
|
||||
var updatedCodeBehindPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !codeBehindPath.StartsWith("/")
|
||||
? '/' + codeBehindPath
|
||||
: codeBehindPath;
|
||||
|
||||
var codeBehindUri = new UriBuilder
|
||||
{
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
Path = codeBehindPath,
|
||||
Path = updatedCodeBehindPath,
|
||||
Host = string.Empty,
|
||||
}.Uri;
|
||||
|
||||
|
|
|
@ -188,17 +188,27 @@ internal class RenameEndpoint : AbstractRazorDelegatingEndpoint<RenameParamsBrid
|
|||
}
|
||||
}
|
||||
|
||||
public static void AddFileRenameForComponent(List<SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>> documentChanges, DocumentSnapshot documentSnapshot, string newPath)
|
||||
public void AddFileRenameForComponent(List<SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>> documentChanges, DocumentSnapshot documentSnapshot, string newPath)
|
||||
{
|
||||
// VS Code in Windows expects path to start with '/'
|
||||
var updatedOldPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !documentSnapshot.FilePath.StartsWith("/")
|
||||
? '/' + documentSnapshot.FilePath
|
||||
: documentSnapshot.FilePath;
|
||||
var oldUri = new UriBuilder
|
||||
{
|
||||
Path = documentSnapshot.FilePath,
|
||||
Path = updatedOldPath,
|
||||
Host = string.Empty,
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
}.Uri;
|
||||
|
||||
// VS Code in Windows expects path to start with '/'
|
||||
var updatedNewPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !newPath.StartsWith("/")
|
||||
? '/' + newPath
|
||||
: newPath;
|
||||
var newUri = new UriBuilder
|
||||
{
|
||||
Path = newPath,
|
||||
|
||||
Path = updatedNewPath,
|
||||
Host = string.Empty,
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
}.Uri;
|
||||
|
@ -219,7 +229,7 @@ internal class RenameEndpoint : AbstractRazorDelegatingEndpoint<RenameParamsBrid
|
|||
return newPath;
|
||||
}
|
||||
|
||||
private static async Task AddEditsForCodeDocumentAsync(
|
||||
private async Task AddEditsForCodeDocumentAsync(
|
||||
List<SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>> documentChanges,
|
||||
IReadOnlyList<TagHelperDescriptor> originTagHelpers,
|
||||
string newName,
|
||||
|
@ -241,9 +251,13 @@ internal class RenameEndpoint : AbstractRazorDelegatingEndpoint<RenameParamsBrid
|
|||
return;
|
||||
}
|
||||
|
||||
// VS Code in Windows expects path to start with '/'
|
||||
var updatedPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !documentSnapshot.FilePath.StartsWith("/")
|
||||
? "/" + documentSnapshot.FilePath
|
||||
: documentSnapshot.FilePath;
|
||||
var uri = new UriBuilder
|
||||
{
|
||||
Path = documentSnapshot.FilePath,
|
||||
Path = updatedPath,
|
||||
Host = string.Empty,
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
}.Uri;
|
||||
|
|
|
@ -21,6 +21,10 @@ internal abstract class LanguageServerFeatureOptions
|
|||
|
||||
public abstract bool SupportsDelegatedCodeActions { get; }
|
||||
|
||||
// Code action and rename paths in Windows VS Code need to be prefixed with '/':
|
||||
// https://github.com/dotnet/razor/issues/8131
|
||||
public abstract bool ReturnCodeActionAndRenamePathsWithPrefixedSlash { get; }
|
||||
|
||||
public string GetRazorCSharpFilePath(string razorFilePath) => razorFilePath + CSharpVirtualDocumentSuffix;
|
||||
|
||||
public string GetRazorHtmlFilePath(string razorFilePath) => razorFilePath + HtmlVirtualDocumentSuffix;
|
||||
|
|
|
@ -60,5 +60,7 @@ internal class VisualStudioWindowsLanguageServerFeatureOptions : LanguageServerF
|
|||
|
||||
public override bool SupportsDelegatedCodeActions => true;
|
||||
|
||||
public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash => false;
|
||||
|
||||
private bool IsCodespacesOrLiveshare => _lspEditorFeatureDetector.IsRemoteClient() || _lspEditorFeatureDetector.IsLiveShareHost();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ internal class VisualStudioMacLanguageServerFeatureOptions : LanguageServerFeatu
|
|||
|
||||
public override bool SupportsDelegatedCodeActions => true;
|
||||
|
||||
public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash => false;
|
||||
|
||||
private bool IsCodespacesOrLiveshare => _lspEditorFeatureDetector.IsRemoteClient() || _lspEditorFeatureDetector.IsLiveShareHost();
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class CreateComponentCodeActionResolverTest : LanguageServerTestBase
|
|||
public async Task Handle_MissingFile()
|
||||
{
|
||||
// Arrange
|
||||
var resolver = new CreateComponentCodeActionResolver(_emptyDocumentContextFactory);
|
||||
var resolver = new CreateComponentCodeActionResolver(_emptyDocumentContextFactory, TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new CreateComponentCodeActionParams()
|
||||
{
|
||||
Uri = new Uri("c:/Test.razor"),
|
||||
|
@ -59,7 +59,7 @@ public class CreateComponentCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
codeDocument.SetUnsupported();
|
||||
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new CreateComponentCodeActionParams()
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
@ -82,7 +82,7 @@ public class CreateComponentCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
codeDocument.SetFileKind(FileKinds.Legacy);
|
||||
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new CreateComponentCodeActionParams()
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
@ -104,7 +104,7 @@ public class CreateComponentCodeActionResolverTest : LanguageServerTestBase
|
|||
var contents = $"@page \"/test\"";
|
||||
var codeDocument = CreateCodeDocument(contents);
|
||||
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var actionParams = new CreateComponentCodeActionParams
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
@ -132,7 +132,7 @@ public class CreateComponentCodeActionResolverTest : LanguageServerTestBase
|
|||
var contents = $"@page \"/test\"{Environment.NewLine}@namespace Another.Namespace";
|
||||
var codeDocument = CreateCodeDocument(contents);
|
||||
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new CreateComponentCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var actionParams = new CreateComponentCodeActionParams
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
|
|
@ -39,7 +39,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
public async Task Handle_MissingFile()
|
||||
{
|
||||
// Arrange
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(_emptyDocumentContextFactory);
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(_emptyDocumentContextFactory, TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams()
|
||||
{
|
||||
Uri = new Uri("c:/Test.razor"),
|
||||
|
@ -66,7 +66,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
codeDocument.SetUnsupported();
|
||||
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams()
|
||||
{
|
||||
Uri = new Uri("c:/Test.razor"),
|
||||
|
@ -93,7 +93,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
codeDocument.SetFileKind(FileKinds.Legacy);
|
||||
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams()
|
||||
{
|
||||
Uri = new Uri("c:/Test.razor"),
|
||||
|
@ -120,7 +120,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
Assert.True(codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace));
|
||||
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var actionParams = new ExtractToCodeBehindCodeActionParams
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
@ -169,7 +169,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
Assert.True(codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace));
|
||||
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var actionParams = new ExtractToCodeBehindCodeActionParams
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
@ -218,7 +218,7 @@ public class ExtractToCodeBehindCodeActionResolverTest : LanguageServerTestBase
|
|||
var codeDocument = CreateCodeDocument(contents);
|
||||
Assert.True(codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace));
|
||||
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument));
|
||||
var resolver = new ExtractToCodeBehindCodeActionResolver(CreateDocumentContextFactory(documentPath, codeDocument), TestLanguageServerFeatureOptions.Instance);
|
||||
var actionParams = new ExtractToCodeBehindCodeActionParams
|
||||
{
|
||||
Uri = documentPath,
|
||||
|
|
|
@ -47,7 +47,7 @@ public class RenameEndpointTest : LanguageServerTestBase
|
|||
public async Task Handle_Rename_FileManipulationNotSupported_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == false, MockBehavior.Strict);
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == false && options.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false, MockBehavior.Strict);
|
||||
var endpoint = CreateEndpoint(languageServerFeatureOptions);
|
||||
var uri = new Uri("file:///c:/First/Component1.razor");
|
||||
var request = new RenameParamsBridge
|
||||
|
@ -421,7 +421,8 @@ public class RenameEndpointTest : LanguageServerTestBase
|
|||
public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer()
|
||||
{
|
||||
// Arrange
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == true && options.SingleServerSupport == true, MockBehavior.Strict);
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(
|
||||
options => options.SupportsFileManipulation == true && options.SingleServerSupport == true && options.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false, MockBehavior.Strict);
|
||||
|
||||
var delegatedEdit = new WorkspaceEdit();
|
||||
|
||||
|
@ -469,7 +470,8 @@ public class RenameEndpointTest : LanguageServerTestBase
|
|||
public async Task Handle_Rename_SingleServer_DoesntDelegateForRazor()
|
||||
{
|
||||
// Arrange
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == true && options.SingleServerSupport == true, MockBehavior.Strict);
|
||||
var languageServerFeatureOptions = Mock.Of<LanguageServerFeatureOptions>(
|
||||
options => options.SupportsFileManipulation == true && options.SingleServerSupport == true && options.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false, MockBehavior.Strict);
|
||||
var languageServerMock = new Mock<ClientNotifierServiceBase>(MockBehavior.Strict);
|
||||
var documentMappingServiceMock = new Mock<RazorDocumentMappingService>(MockBehavior.Strict);
|
||||
documentMappingServiceMock
|
||||
|
@ -640,7 +642,8 @@ public class RenameEndpointTest : LanguageServerTestBase
|
|||
d.TryCreateAsync(new Uri(itemDirectory2.FilePath), It.IsAny<CancellationToken>()) == Task.FromResult(directory2Component), MockBehavior.Strict);
|
||||
|
||||
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, projectSnapshotManagerAccessor, LoggerFactory);
|
||||
languageServerFeatureOptions ??= Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == true && options.SingleServerSupport == false, MockBehavior.Strict);
|
||||
languageServerFeatureOptions ??= Mock.Of<LanguageServerFeatureOptions>(
|
||||
options => options.SupportsFileManipulation == true && options.SingleServerSupport == false && options.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false, MockBehavior.Strict);
|
||||
|
||||
var documentMappingServiceMock = new Mock<RazorDocumentMappingService>(MockBehavior.Strict);
|
||||
documentMappingServiceMock
|
||||
|
|
|
@ -26,4 +26,6 @@ internal class TestLanguageServerFeatureOptions : LanguageServerFeatureOptions
|
|||
public override bool SingleServerSupport => false;
|
||||
|
||||
public override bool SupportsDelegatedCodeActions => false;
|
||||
|
||||
public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash => false;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче