зеркало из https://github.com/dotnet/razor.git
Add a code action to promote a using directive
This commit is contained in:
Родитель
fa5b57f1c7
Коммит
a5a55ea9e9
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
|||
|
||||
internal class MvcImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
|
||||
{
|
||||
private const string ImportsFileName = "_ViewImports.cshtml";
|
||||
internal const string ImportsFileName = "_ViewImports.cshtml";
|
||||
|
||||
public IReadOnlyList<RazorProjectItem> GetImports(RazorProjectItem projectItem)
|
||||
{
|
||||
|
|
|
@ -155,6 +155,8 @@ internal static class IServiceCollectionExtensions
|
|||
services.AddSingleton<IRazorCodeActionResolver, AddUsingsCodeActionResolver>();
|
||||
services.AddSingleton<IRazorCodeActionProvider, GenerateMethodCodeActionProvider>();
|
||||
services.AddSingleton<IRazorCodeActionResolver, GenerateMethodCodeActionResolver>();
|
||||
services.AddSingleton<IRazorCodeActionProvider, PromoteUsingCodeActionProvider>();
|
||||
services.AddSingleton<IRazorCodeActionResolver, PromoteUsingCodeActionResolver>();
|
||||
|
||||
// Html Code actions
|
||||
services.AddSingleton<IHtmlCodeActionProvider, HtmlCodeActionProvider>();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// 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.Serialization;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Razor.CodeActions.Models;
|
||||
|
||||
internal sealed class PromoteToUsingCodeActionParams
|
||||
{
|
||||
[JsonPropertyName("importsFileName")]
|
||||
public required string ImportsFileName { get; init; }
|
||||
|
||||
[JsonPropertyName("usingDirective")]
|
||||
public required string UsingDirective { get; init; }
|
||||
|
||||
[JsonPropertyName("removeStart")]
|
||||
public required int RemoveStart { get; init; }
|
||||
|
||||
[JsonPropertyName("removeEnd")]
|
||||
public required int RemoveEnd { get; init; }
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// 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.Immutable;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.Language.Components;
|
||||
using Microsoft.AspNetCore.Razor.Language.Syntax;
|
||||
using Microsoft.AspNetCore.Razor.Threading;
|
||||
using Microsoft.CodeAnalysis.Razor.CodeActions.Models;
|
||||
using Microsoft.CodeAnalysis.Razor.CodeActions.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Protocol;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Razor.CodeActions;
|
||||
|
||||
internal class PromoteUsingCodeActionProvider : IRazorCodeActionProvider
|
||||
{
|
||||
public Task<ImmutableArray<RazorVSInternalCodeAction>> ProvideAsync(RazorCodeActionContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
if (context.HasSelection)
|
||||
{
|
||||
return SpecializedTasks.EmptyImmutableArray<RazorVSInternalCodeAction>();
|
||||
}
|
||||
|
||||
var syntaxTree = context.CodeDocument.GetSyntaxTree();
|
||||
if (syntaxTree?.Root is null)
|
||||
{
|
||||
return SpecializedTasks.EmptyImmutableArray<RazorVSInternalCodeAction>();
|
||||
}
|
||||
|
||||
var owner = syntaxTree.Root.FindNode(TextSpan.FromBounds(context.StartAbsoluteIndex, context.EndAbsoluteIndex));
|
||||
if (owner is null)
|
||||
{
|
||||
return SpecializedTasks.EmptyImmutableArray<RazorVSInternalCodeAction>();
|
||||
}
|
||||
|
||||
if (owner.FirstAncestorOrSelf<RazorDirectiveSyntax>() is not { } directive ||
|
||||
!directive.IsUsingDirective(out _))
|
||||
{
|
||||
return SpecializedTasks.EmptyImmutableArray<RazorVSInternalCodeAction>();
|
||||
}
|
||||
|
||||
var importFileName = FileKinds.IsLegacy(context.DocumentSnapshot.FileKind)
|
||||
? MvcImportProjectFeature.ImportsFileName
|
||||
: ComponentMetadata.ImportsFileName;
|
||||
|
||||
var line = context.CodeDocument.Source.Text.Lines.GetLineFromPosition(context.StartAbsoluteIndex);
|
||||
var data = new PromoteToUsingCodeActionParams
|
||||
{
|
||||
ImportsFileName = importFileName,
|
||||
UsingDirective = directive.GetContent(),
|
||||
RemoveStart = line.Start,
|
||||
RemoveEnd = line.EndIncludingLineBreak
|
||||
};
|
||||
|
||||
var resolutionParams = new RazorCodeActionResolutionParams()
|
||||
{
|
||||
TextDocument = context.Request.TextDocument,
|
||||
Action = LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
Language = RazorLanguageKind.Razor,
|
||||
DelegatedDocumentUri = context.DelegatedDocumentUri,
|
||||
Data = data
|
||||
};
|
||||
|
||||
var action = RazorCodeActionFactory.CreatePromoteUsingDirective(importFileName, resolutionParams);
|
||||
|
||||
return Task.FromResult<ImmutableArray<RazorVSInternalCodeAction>>([action]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// 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.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.AspNetCore.Razor.Utilities;
|
||||
using Microsoft.CodeAnalysis.Razor.CodeActions.Models;
|
||||
using Microsoft.CodeAnalysis.Razor.Formatting;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Razor.Protocol;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Razor.CodeActions;
|
||||
|
||||
internal class PromoteUsingCodeActionResolver(IFileSystem fileSystem) : IRazorCodeActionResolver
|
||||
{
|
||||
private readonly IFileSystem _fileSystem = fileSystem;
|
||||
|
||||
public string Action => LanguageServerConstants.CodeActions.PromoteUsingDirective;
|
||||
|
||||
public async Task<WorkspaceEdit?> ResolveAsync(DocumentContext documentContext, JsonElement data, RazorFormattingOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var actionParams = data.Deserialize<PromoteToUsingCodeActionParams>();
|
||||
if (actionParams is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (codeDocument.IsUnsupported())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var file = FilePathNormalizer.Normalize(documentContext.Uri.GetAbsoluteOrUNCPath());
|
||||
var folder = Path.GetDirectoryName(file).AssumeNotNull();
|
||||
var importsFile = Path.GetFullPath(Path.Combine(folder, "..", actionParams.ImportsFileName));
|
||||
var importFileUri = new UriBuilder
|
||||
{
|
||||
Scheme = Uri.UriSchemeFile,
|
||||
Path = importsFile,
|
||||
Host = string.Empty,
|
||||
}.Uri;
|
||||
|
||||
using var edits = new PooledArrayBuilder<SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>>();
|
||||
|
||||
var textToInsert = actionParams.UsingDirective;
|
||||
var insertLocation = new LinePosition(0, 0);
|
||||
if (!_fileSystem.FileExists(importsFile))
|
||||
{
|
||||
edits.Add(new CreateFile() { Uri = importFileUri });
|
||||
}
|
||||
else
|
||||
{
|
||||
var st = SourceText.From(_fileSystem.ReadFile(importsFile));
|
||||
var lastLine = st.Lines[st.Lines.Count - 1];
|
||||
insertLocation = new LinePosition(lastLine.LineNumber, 0);
|
||||
if (lastLine.GetFirstNonWhitespaceOffset() is { } nonWhiteSpaceOffset)
|
||||
{
|
||||
// Last line isn't blank, so add a newline, and insert at the end
|
||||
textToInsert = Environment.NewLine + textToInsert;
|
||||
insertLocation = new LinePosition(insertLocation.Line, lastLine.SpanIncludingLineBreak.Length);
|
||||
}
|
||||
}
|
||||
|
||||
edits.Add(new TextDocumentEdit
|
||||
{
|
||||
TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = importFileUri },
|
||||
Edits = [VsLspFactory.CreateTextEdit(insertLocation, textToInsert)]
|
||||
});
|
||||
|
||||
var removeRange = codeDocument.Source.Text.GetRange(actionParams.RemoveStart, actionParams.RemoveEnd);
|
||||
|
||||
edits.Add(new TextDocumentEdit
|
||||
{
|
||||
TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = documentContext.Uri },
|
||||
Edits = [VsLspFactory.CreateTextEdit(removeRange, string.Empty)]
|
||||
});
|
||||
|
||||
return new WorkspaceEdit
|
||||
{
|
||||
DocumentChanges = edits.ToArray()
|
||||
};
|
||||
}
|
||||
}
|
|
@ -18,6 +18,16 @@ internal static class RazorCodeActionFactory
|
|||
private readonly static Guid s_createExtractToComponentTelemetryId = new("af67b0a3-f84b-4808-97a7-b53e85b22c64");
|
||||
private readonly static Guid s_generateMethodTelemetryId = new("c14fa003-c752-45fc-bb29-3a123ae5ecef");
|
||||
private readonly static Guid s_generateAsyncMethodTelemetryId = new("9058ca47-98e2-4f11-bf7c-a16a444dd939");
|
||||
private readonly static Guid s_promoteUsingDirectiveTelemetryId = new("751f9012-e37b-444a-9211-b4ebce91d96e");
|
||||
|
||||
public static RazorVSInternalCodeAction CreatePromoteUsingDirective(string importsFileName, RazorCodeActionResolutionParams resolutionParams)
|
||||
=> new RazorVSInternalCodeAction
|
||||
{
|
||||
Title = SR.FormatPromote_using_directive_to(importsFileName),
|
||||
Data = JsonSerializer.SerializeToElement(resolutionParams),
|
||||
TelemetryId = s_promoteUsingDirectiveTelemetryId,
|
||||
Name = LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
};
|
||||
|
||||
public static RazorVSInternalCodeAction CreateAddComponentUsing(string @namespace, string? newTagName, RazorCodeActionResolutionParams resolutionParams)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,8 @@ internal static class LanguageServerConstants
|
|||
|
||||
public const string AddUsing = "AddUsing";
|
||||
|
||||
public const string PromoteUsingDirective = "PromoteUsingDirective";
|
||||
|
||||
public const string CodeActionFromVSCode = "CodeActionFromVSCode";
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -196,4 +196,7 @@
|
|||
<data name="Statement" xml:space="preserve">
|
||||
<value>statement</value>
|
||||
</data>
|
||||
<data name="Promote_using_directive_to" xml:space="preserve">
|
||||
<value>Promote using directive to {0}</value>
|
||||
</data>
|
||||
</root>
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">Proběhl dotaz na řádek {0} mimo rozsah {1} {2}. Dokument nemusí být aktuální.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">příkaz</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">Die Zeile "{0}" außerhalb des {1} Bereichs von "{2}" wurde abgefragt. Das Dokument ist möglicherweise nicht auf dem neuesten Stand.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">Anweisung</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">La línea '{0}' se consultó fuera del {1} rango de '{2}'. Es posible que el documento no esté actualizado.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">instrucción</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">La ligne «{0}» en dehors de la plage{1} de «{2}» a été interrogée. Le document n’est peut-être pas à jour.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">déclaration</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">È stata eseguita una query sulla riga '{0}' non compresa nell'intervallo {1} di '{2}'. Il documento potrebbe non essere aggiornato.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">istruzione</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">'{2}' の {1} 範囲外の行 '{0}' がクエリされました。ドキュメントが最新ではない可能性があります。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">ステートメント</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">'{2}'의 {1} 범위를 벗어나는 줄 '{0}'을(를) 쿼리했습니다. 문서가 최신이 아닐 수 있습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">문</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">Wykonano zapytanie wiersza "{0}" poza zakresem {1} "{2}". Dokument może być nieaktualny.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">instrukcja</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">A linha '{0}' fora do intervalo {1} de '{2}' foi consultada. O documento pode não estar atualizado.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">instrução</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">Запрошена строка "{0}" за пределами диапазона {1} "{2}". Возможно, документ не обновлен.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">инструкция</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">{1} / '{2}' aralığının dışındaki '{0}' satırı sorgulandı. Belge güncel olmayabilir.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">deyim</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">查询了 "{0}" 的 {1} 范围外的行 "{2}"。文档可能不是最新的。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">语句</target>
|
||||
|
|
|
@ -104,6 +104,11 @@
|
|||
<target state="translated">已查詢 '{2}' 之 {1} 範圍以外的行 '{0}'。文件可能不是最新狀態。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Promote_using_directive_to">
|
||||
<source>Promote using directive to {0}</source>
|
||||
<target state="new">Promote using directive to {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="Statement">
|
||||
<source>statement</source>
|
||||
<target state="translated">陳述式</target>
|
||||
|
|
|
@ -49,6 +49,9 @@ internal sealed class OOPComponentAccessibilityCodeActionProvider(IFileSystem fi
|
|||
[Export(typeof(IRazorCodeActionProvider)), Shared]
|
||||
internal sealed class OOPGenerateMethodCodeActionProvider : GenerateMethodCodeActionProvider;
|
||||
|
||||
[Export(typeof(IRazorCodeActionProvider)), Shared]
|
||||
internal sealed class OOPPromoteUsingDirectiveCodeActionProvider : PromoteUsingCodeActionProvider;
|
||||
|
||||
[Export(typeof(ICSharpCodeActionProvider)), Shared]
|
||||
internal sealed class OOPTypeAccessibilityCodeActionProvider : TypeAccessibilityCodeActionProvider;
|
||||
|
||||
|
@ -89,6 +92,10 @@ internal sealed class OOPGenerateMethodCodeActionResolver(
|
|||
IFileSystem fileSystem)
|
||||
: GenerateMethodCodeActionResolver(roslynCodeActionHelpers, documentMappingService, razorFormattingService, fileSystem);
|
||||
|
||||
[Export(typeof(IRazorCodeActionResolver)), Shared]
|
||||
[method: ImportingConstructor]
|
||||
internal sealed class OOPPromoteUsingDirectiveCodeActionResolver(IFileSystem fileSystem) : PromoteUsingCodeActionResolver(fileSystem);
|
||||
|
||||
[Export(typeof(ICSharpCodeActionResolver)), Shared]
|
||||
[method: ImportingConstructor]
|
||||
internal sealed class OOPCSharpCodeActionResolver(IRazorFormattingService razorFormattingService) : CSharpCodeActionResolver(razorFormattingService);
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.AspNetCore.Razor.Telemetry;
|
||||
using Microsoft.AspNetCore.Razor.Test.Common;
|
||||
|
@ -15,6 +16,7 @@ using Microsoft.CodeAnalysis;
|
|||
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.CodeActions.Models;
|
||||
using Microsoft.CodeAnalysis.Razor.Protocol;
|
||||
using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
using Microsoft.CodeAnalysis.Remote.Razor;
|
||||
|
@ -24,8 +26,8 @@ using Microsoft.VisualStudio.Razor.Settings;
|
|||
using Roslyn.Test.Utilities;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using WorkspacesSR = Microsoft.CodeAnalysis.Razor.Workspaces.Resources.SR;
|
||||
using LspDiagnostic = Microsoft.VisualStudio.LanguageServer.Protocol.Diagnostic;
|
||||
using WorkspacesSR = Microsoft.CodeAnalysis.Razor.Workspaces.Resources.SR;
|
||||
|
||||
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
|
||||
|
||||
|
@ -870,6 +872,150 @@ public class CohostCodeActionsEndpointTest(ITestOutputHelper testOutputHelper) :
|
|||
""")]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PromoteUsingDirective()
|
||||
{
|
||||
await VerifyCodeActionAsync(
|
||||
input: """
|
||||
@using [||]System
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
expected: """
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
additionalExpectedFiles: [
|
||||
(FileUri(@"..\_Imports.razor"), """
|
||||
@using System
|
||||
""")]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PromoteUsingDirective_Mvc()
|
||||
{
|
||||
await VerifyCodeActionAsync(
|
||||
input: """
|
||||
@using [||]System
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
expected: """
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
fileKind: FileKinds.Legacy,
|
||||
additionalExpectedFiles: [
|
||||
(FileUri(@"..\_ViewImports.cshtml"), """
|
||||
@using System
|
||||
""")]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PromoteUsingDirective_ExistingImports()
|
||||
{
|
||||
await VerifyCodeActionAsync(
|
||||
input: """
|
||||
@using [||]System
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
additionalFiles: [
|
||||
(FilePath(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
""")],
|
||||
expected: """
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
additionalExpectedFiles: [
|
||||
(FileUri(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
@using System
|
||||
""")]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PromoteUsingDirective_ExistingImports_BlankLineAtEnd()
|
||||
{
|
||||
await VerifyCodeActionAsync(
|
||||
input: """
|
||||
@using [||]System
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
additionalFiles: [
|
||||
(FilePath(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
|
||||
""")],
|
||||
expected: """
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
additionalExpectedFiles: [
|
||||
(FileUri(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
@using System
|
||||
""")]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PromoteUsingDirective_ExistingImports_WhitespaceLineAtEnd()
|
||||
{
|
||||
await VerifyCodeActionAsync(
|
||||
input: """
|
||||
@using [||]System
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
additionalFiles: [
|
||||
(FilePath(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
|
||||
""")],
|
||||
expected: """
|
||||
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
""",
|
||||
codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective,
|
||||
additionalExpectedFiles: [
|
||||
(FileUri(@"..\_Imports.razor"), """
|
||||
@using System.Text
|
||||
@using Foo.Bar
|
||||
@using System
|
||||
""")]);
|
||||
}
|
||||
|
||||
private async Task VerifyCodeActionAsync(TestCode input, string? expected, string codeActionName, int childActionIndex = 0, string? fileKind = null, (string filePath, string contents)[]? additionalFiles = null, (Uri fileUri, string contents)[]? additionalExpectedFiles = null)
|
||||
{
|
||||
var fileSystem = (RemoteFileSystem)OOPExportProvider.GetExportedValue<IFileSystem>();
|
||||
|
@ -905,7 +1051,7 @@ public class CohostCodeActionsEndpointTest(ITestOutputHelper testOutputHelper) :
|
|||
await VerifyCodeActionResultAsync(document, workspaceEdit, expected, additionalExpectedFiles);
|
||||
}
|
||||
|
||||
private async Task<CodeAction?> VerifyCodeActionRequestAsync(CodeAnalysis.TextDocument document, TestCode input, string codeActionName, int childActionIndex)
|
||||
private async Task<CodeAction?> VerifyCodeActionRequestAsync(TextDocument document, TestCode input, string codeActionName, int childActionIndex)
|
||||
{
|
||||
var requestInvoker = new TestLSPRequestInvoker();
|
||||
var endpoint = new CohostCodeActionsEndpoint(RemoteServiceInvoker, ClientCapabilitiesService, TestHtmlDocumentSynchronizer.Instance, requestInvoker, NoOpTelemetryReporter.Instance);
|
||||
|
|
|
@ -272,5 +272,5 @@ public abstract class CohostEndpointTestBase(ITestOutputHelper testOutputHelper)
|
|||
=> new(FilePath(projectRelativeFileName));
|
||||
|
||||
protected static string FilePath(string projectRelativeFileName)
|
||||
=> Path.Combine(TestProjectData.SomeProjectPath, projectRelativeFileName);
|
||||
=> Path.GetFullPath(Path.Combine(TestProjectData.SomeProjectPath, projectRelativeFileName));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче