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 5f300cb9c96..19d31766f04 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs @@ -171,7 +171,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V // For C# we run the edit through our formatting engine Debug.Assert(positionInfo.LanguageKind == RazorLanguageKind.CSharp); - var options = RazorFormattingOptions.From(originalRequest.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(originalRequest.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); var textChange = csharpSourceText.GetTextChange(delegatedResponse.TextEdit); 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 f73bc3baf3c..1bbce9f198f 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 @@ -99,7 +99,7 @@ private async Task PostProcessCompletionItemAsync( return resolvedCompletionItem; } - var options = RazorFormattingOptions.From(formattingOptions, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(formattingOptions, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); return await DelegatedCompletionHelper.FormatCSharpCompletionItemAsync( resolvedCompletionItem, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorConfigurationService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorConfigurationService.cs index 231a7529ee0..c180fe4a727 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorConfigurationService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorConfigurationService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Settings; @@ -95,13 +96,14 @@ internal RazorLSPOptions BuildOptions(JsonObject[] result) } else { - ExtractVSCodeOptions(result, out var formatting, out var autoClosingTags, out var commitElementsWithSpace, out var codeBlockBraceOnNextLine); + ExtractVSCodeOptions(result, out var formatting, out var autoClosingTags, out var commitElementsWithSpace, out var codeBlockBraceOnNextLine, out var attributeIndentStyle); return RazorLSPOptions.Default with { Formatting = formatting, AutoClosingTags = autoClosingTags, CommitElementsWithSpace = commitElementsWithSpace, - CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine + CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine, + AttributeIndentStyle = attributeIndentStyle, }; } } @@ -111,7 +113,8 @@ private void ExtractVSCodeOptions( out FormattingFlags formatting, out bool autoClosingTags, out bool commitElementsWithSpace, - out bool codeBlockBraceOnNextLine) + out bool codeBlockBraceOnNextLine, + out AttributeIndentStyle attributeIndentStyle) { var razor = result[0]; var html = result[1]; @@ -122,6 +125,7 @@ private void ExtractVSCodeOptions( // Deliberately not using the "default" here because we want a different default for VS Code, as // this matches VS Code's html servers commit behaviour commitElementsWithSpace = false; + attributeIndentStyle = RazorLSPOptions.Default.AttributeIndentStyle; if (razor.TryGetPropertyValue("format", out var parsedFormatNode) && parsedFormatNode?.AsObject() is { } parsedFormat) @@ -145,6 +149,12 @@ private void ExtractVSCodeOptions( { codeBlockBraceOnNextLine = GetObjectOrDefault(parsedCodeBlockBraceOnNextLine, codeBlockBraceOnNextLine); } + + if (parsedFormat.TryGetPropertyValue("attributeIndentStyle", out var parsedAttributeIndentStyle) && + parsedAttributeIndentStyle is not null) + { + attributeIndentStyle = GetEnumValue(parsedAttributeIndentStyle, AttributeIndentStyle.AlignWithFirst); + } } if (razor.TryGetPropertyValue("completion", out var parsedCompletionNode) && @@ -212,4 +222,26 @@ private T GetObjectOrDefault(JsonNode token, T defaultValue, [CallerArgumentE return defaultValue; } } + + private T GetEnumValue(JsonNode token, T defaultValue, [CallerArgumentExpression(nameof(defaultValue))] string? expression = null) + where T : struct + { + try + { + // GetValue could potentially throw here if the user provides malformed options. + // If this occurs, catch the exception and return the default value. + if (token.GetValue() is { } stringValue && + Enum.TryParse(stringValue, ignoreCase: true, out var parsed)) + { + return parsed; + } + + return defaultValue; + } + catch (Exception ex) + { + _logger.LogError(ex, $"Malformed option: Token {token} cannot be converted to type {typeof(T)} for {expression}."); + return defaultValue; + } + } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentFormattingEndpoint.cs index d51eaca2e37..59aed893731 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentFormattingEndpoint.cs @@ -49,7 +49,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentFormattingParams var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); if (await _htmlFormatter.GetDocumentFormattingEditsAsync( documentContext.Snapshot, 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 77666e570f4..6f654e8b3e2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs @@ -91,7 +91,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentOnTypeFormatting cancellationToken.ThrowIfCancellationRequested(); - var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); ImmutableArray formattedChanges; if (triggerCharacterKind == RazorLanguageKind.CSharp) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentRangeFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentRangeFormattingEndpoint.cs index ea308fee08c..2908fccb9f2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentRangeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentRangeFormattingEndpoint.cs @@ -61,7 +61,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentRangeFormattingP } } - var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); if (await _htmlFormatter.GetDocumentFormattingEditsAsync( documentContext.Snapshot, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hosting/RazorLSPOptions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hosting/RazorLSPOptions.cs index 509bf9c6a58..e13b7c17421 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hosting/RazorLSPOptions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hosting/RazorLSPOptions.cs @@ -19,6 +19,7 @@ internal sealed record RazorLSPOptions( bool AutoInsertAttributeQuotes, bool ColorBackground, bool CodeBlockBraceOnNextLine, + AttributeIndentStyle AttributeIndentStyle, bool CommitElementsWithSpace, ImmutableArray TaskListDescriptors) { @@ -31,6 +32,7 @@ internal sealed record RazorLSPOptions( AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: false, + AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: true, TaskListDescriptors: []); @@ -47,16 +49,17 @@ public ImmutableArray TaskListDescriptors /// internal static RazorLSPOptions From(ClientSettings settings) => new(GetFormattingFlags(settings), - settings.AdvancedSettings.AutoClosingTags, - !settings.ClientSpaceSettings.IndentWithTabs, - settings.ClientSpaceSettings.IndentSize, - settings.ClientCompletionSettings.AutoShowCompletion, - settings.ClientCompletionSettings.AutoListParams, - settings.AdvancedSettings.AutoInsertAttributeQuotes, - settings.AdvancedSettings.ColorBackground, - settings.AdvancedSettings.CodeBlockBraceOnNextLine, - settings.AdvancedSettings.CommitElementsWithSpace, - settings.AdvancedSettings.TaskListDescriptors); + settings.AdvancedSettings.AutoClosingTags, + !settings.ClientSpaceSettings.IndentWithTabs, + settings.ClientSpaceSettings.IndentSize, + settings.ClientCompletionSettings.AutoShowCompletion, + settings.ClientCompletionSettings.AutoListParams, + settings.AdvancedSettings.AutoInsertAttributeQuotes, + settings.AdvancedSettings.ColorBackground, + settings.AdvancedSettings.CodeBlockBraceOnNextLine, + settings.AdvancedSettings.AttributeIndentStyle, + settings.AdvancedSettings.CommitElementsWithSpace, + settings.AdvancedSettings.TaskListDescriptors); private static FormattingFlags GetFormattingFlags(ClientSettings settings) { @@ -86,6 +89,7 @@ public bool Equals(RazorLSPOptions? other) AutoInsertAttributeQuotes == other.AutoInsertAttributeQuotes && ColorBackground == other.ColorBackground && CodeBlockBraceOnNextLine == other.CodeBlockBraceOnNextLine && + AttributeIndentStyle == other.AttributeIndentStyle && CommitElementsWithSpace == other.CommitElementsWithSpace && TaskListDescriptors.SequenceEqual(other.TaskListDescriptors); } @@ -102,6 +106,7 @@ public override int GetHashCode() hash.Add(AutoInsertAttributeQuotes); hash.Add(ColorBackground); hash.Add(CodeBlockBraceOnNextLine); + hash.Add(AttributeIndentStyle); hash.Add(CommitElementsWithSpace); hash.Add(TaskListDescriptors); return hash; 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 6cb84700da1..aa8ceb209d8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs @@ -103,7 +103,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti continue; } - var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine, _optionsMonitor.CurrentValue.AttributeIndentStyle); var formattingContext = FormattingContext.Create( documentContext.Snapshot, codeDocument, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CodeActions/CohostCodeActionsResolveEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CodeActions/CohostCodeActionsResolveEndpoint.cs index 1e2f376c4cf..9f91658e878 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CodeActions/CohostCodeActionsResolveEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CodeActions/CohostCodeActionsResolveEndpoint.cs @@ -86,7 +86,8 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie { InsertSpaces = !clientSettings.ClientSpaceSettings.IndentWithTabs, TabSize = clientSettings.ClientSpaceSettings.IndentSize, - CodeBlockBraceOnNextLine = clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine + CodeBlockBraceOnNextLine = clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine, + AttributeIndentStyle = clientSettings.AdvancedSettings.AttributeIndentStyle, }; return await _remoteServiceInvoker.TryInvokeAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionResolveEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionResolveEndpoint.cs index fb56b0ee2b7..3c674219b79 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionResolveEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionResolveEndpoint.cs @@ -135,7 +135,8 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie { InsertSpaces = !clientSettings.ClientSpaceSettings.IndentWithTabs, TabSize = clientSettings.ClientSpaceSettings.IndentSize, - CodeBlockBraceOnNextLine = clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine + CodeBlockBraceOnNextLine = clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine, + AttributeIndentStyle = clientSettings.AdvancedSettings.AttributeIndentStyle, }; // Couldn't find an associated completion list, so its either Razor or C#. Either way, over to OOP diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostDocumentFormattingEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostDocumentFormattingEndpoint.cs index e5cc179abda..33ce3bcd442 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostDocumentFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostDocumentFormattingEndpoint.cs @@ -85,6 +85,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie var options = RazorFormattingOptions.From( request.Options, _clientSettingsManager.GetClientSettings().AdvancedSettings.CodeBlockBraceOnNextLine, + _clientSettingsManager.GetClientSettings().AdvancedSettings.AttributeIndentStyle, csharpSyntaxFormattingOptions); _logger.LogDebug($"Calling OOP with the {htmlChanges.Length} html edits, so it can fill in the rest"); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostOnTypeFormattingEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostOnTypeFormattingEndpoint.cs index 0d9d4fb0526..4eb185d1086 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostOnTypeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostOnTypeFormattingEndpoint.cs @@ -113,7 +113,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie } var csharpSyntaxFormattingOptions = RazorCSharpFormattingInteractionService.GetRazorCSharpSyntaxFormattingOptions(razorDocument.Project.Solution.Services); - var options = RazorFormattingOptions.From(request.Options, clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine, csharpSyntaxFormattingOptions); + var options = RazorFormattingOptions.From(request.Options, clientSettings.AdvancedSettings.CodeBlockBraceOnNextLine, clientSettings.AdvancedSettings.AttributeIndentStyle, csharpSyntaxFormattingOptions); _logger.LogDebug($"Calling OOP with the {htmlChanges.Length} html edits, so it can fill in the rest"); var remoteResult = await _remoteServiceInvoker.TryInvokeAsync>( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostRangeFormattingEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostRangeFormattingEndpoint.cs index 26e19d3bf2d..d503be7b1c5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostRangeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Formatting/CohostRangeFormattingEndpoint.cs @@ -88,6 +88,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie var options = RazorFormattingOptions.From( request.Options, _clientSettingsManager.GetClientSettings().AdvancedSettings.CodeBlockBraceOnNextLine, + _clientSettingsManager.GetClientSettings().AdvancedSettings.AttributeIndentStyle, csharpSyntaxFormattingOptions); _logger.LogDebug($"Calling OOP with the {htmlChanges.Length} html edits, so it can fill in the rest"); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/OnAutoInsert/CohostOnAutoInsertEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/OnAutoInsert/CohostOnAutoInsertEndpoint.cs index 9d37546fbc0..ac4939fd606 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/OnAutoInsert/CohostOnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/OnAutoInsert/CohostOnAutoInsertEndpoint.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol.AutoInsert; using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse; @@ -90,7 +91,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie _logger.LogDebug($"Resolving auto-insertion for {razorDocument.FilePath}"); var clientSettings = _clientSettingsManager.GetClientSettings(); - var razorFormattingOptions = RazorFormattingOptions.From(request.Options, codeBlockBraceOnNextLine: false); + var razorFormattingOptions = RazorFormattingOptions.From(request.Options, codeBlockBraceOnNextLine: false, attributeIndentStyle: AttributeIndentStyle.AlignWithFirst); var autoInsertOptions = RemoteAutoInsertOptions.From(clientSettings, razorFormattingOptions); _logger.LogDebug($"Calling OOP to resolve insertion at {request.Position} invoked by typing '{request.Character}'"); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionResolver.cs index 0d44955b109..579a24eedbf 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionResolver.cs @@ -176,7 +176,8 @@ private async Task GenerateMethodInCodeBlockAsync( { TabSize = options.TabSize, InsertSpaces = options.InsertSpaces, - CodeBlockBraceOnNextLine = options.CodeBlockBraceOnNextLine + CodeBlockBraceOnNextLine = options.CodeBlockBraceOnNextLine, + AttributeIndentStyle = options.AttributeIndentStyle, }; var formattedChange = await _razorFormattingService.TryGetCSharpCodeActionEditAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs index 038d895da00..bd587cc945e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; @@ -156,6 +157,7 @@ private sealed class Generator( private readonly SyntaxNode _csharpSyntaxRoot = csharpSyntaxRoot; private readonly bool _insertSpaces = options.InsertSpaces; private readonly int _tabSize = options.TabSize; + private readonly AttributeIndentStyle _attributeIndentStyle = options.AttributeIndentStyle; private readonly RazorCSharpSyntaxFormattingOptions? _csharpSyntaxFormattingOptions = options.CSharpSyntaxFormattingOptions; private readonly StringBuilder _builder = builder; private readonly ImmutableArray.Builder _lineInfoBuilder = lineInfoBuilder; @@ -717,16 +719,23 @@ public override LineInfo VisitMarkupCommentBlock(MarkupCommentBlockSyntax node) { if (RazorSyntaxFacts.IsAttributeName(node, out var startTag)) { - // Attributes are indented to align with the first attribute in their tag. In future, now that we're handling - // this ourselves, we can make this an option: https://github.com/dotnet/razor/issues/6551 - var firstAttribute = startTag.Attributes[0]; - var nameSpan = RazorSyntaxFacts.GetFullAttributeNameSpan(firstAttribute); - - // We need to line up with the first attribute, but the start tag might not be the first thing on the line, - // so it's really relative to the first non-whitespace character on the line. We use the line that the attribute - // is on, just in case its not on the same line as the start tag. - var lineStart = _sourceText.Lines[GetLineNumber(nameSpan)].GetFirstNonWhitespacePosition().GetValueOrDefault(); - var htmlIndentLevel = FormattingUtilities.GetIndentationLevel(nameSpan.Start - lineStart, _tabSize, out var additionalIndentation); + // If we're just indenting attributes by one level, then we don't need to do anything special here. + var htmlIndentLevel = 1; + var additionalIndentation = ""; + + // Otherwise, attributes can be configured to align with the first attribute in their tag. + if (_attributeIndentStyle == AttributeIndentStyle.AlignWithFirst) + { + var firstAttribute = startTag.Attributes[0]; + var nameSpan = RazorSyntaxFacts.GetFullAttributeNameSpan(firstAttribute); + + // We need to line up with the first attribute, but the start tag might not be the first thing on the line, + // so it's really relative to the first non-whitespace character on the line. We use the line that the attribute + // is on, just in case its not on the same line as the start tag. + var lineStart = _sourceText.Lines[GetLineNumber(nameSpan)].GetFirstNonWhitespacePosition().GetValueOrDefault(); + htmlIndentLevel = FormattingUtilities.GetIndentationLevel(nameSpan.Start - lineStart, _tabSize, out additionalIndentation); + } + // If the element has caused indentation, then we'll want to take one level off our attribute indentation to // compensate. Need to be careful here because things like ` 0) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingOptions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingOptions.cs index efecbec1a76..4a2c88865af 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingOptions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingOptions.cs @@ -4,6 +4,7 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; +using Microsoft.CodeAnalysis.Razor.Settings; namespace Microsoft.CodeAnalysis.Razor.Formatting; @@ -17,26 +18,30 @@ internal readonly record struct RazorFormattingOptions [DataMember(Order = 2)] public bool CodeBlockBraceOnNextLine { get; init; } = false; [DataMember(Order = 3)] + public AttributeIndentStyle AttributeIndentStyle { get; init; } = AttributeIndentStyle.AlignWithFirst; + [DataMember(Order = 4)] public RazorCSharpSyntaxFormattingOptions? CSharpSyntaxFormattingOptions { get; init; } public RazorFormattingOptions() { } - public static RazorFormattingOptions From(FormattingOptions options, bool codeBlockBraceOnNextLine) + public static RazorFormattingOptions From(FormattingOptions options, bool codeBlockBraceOnNextLine, AttributeIndentStyle attributeIndentStyle) => new() { InsertSpaces = options.InsertSpaces, TabSize = options.TabSize, - CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine + CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine, + AttributeIndentStyle = attributeIndentStyle, }; - public static RazorFormattingOptions From(FormattingOptions options, bool codeBlockBraceOnNextLine, RazorCSharpSyntaxFormattingOptions csharpSyntaxFormattingOptions) + public static RazorFormattingOptions From(FormattingOptions options, bool codeBlockBraceOnNextLine, AttributeIndentStyle attributeIndentStyle, RazorCSharpSyntaxFormattingOptions csharpSyntaxFormattingOptions) => new() { InsertSpaces = options.InsertSpaces, TabSize = options.TabSize, CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine, + AttributeIndentStyle = attributeIndentStyle, CSharpSyntaxFormattingOptions = csharpSyntaxFormattingOptions }; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/AttributeIndentStyle.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/AttributeIndentStyle.cs new file mode 100644 index 00000000000..b4a77e6fe09 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/AttributeIndentStyle.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.CodeAnalysis.Razor.Settings; + +internal enum AttributeIndentStyle +{ + /// + /// Matches the behaviour of the Html formatter in VS and VS Code, and makes attributes on subsequent lines + /// align with the first attribute on the first line of a tag + /// + AlignWithFirst, + /// + /// Indents attributes on subsequent lines by one more level than the indentation level of the line the tag starts on + /// + IndentByOne +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/ClientSettings.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/ClientSettings.cs index c3caff33e9f..a34ce02d689 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/ClientSettings.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Settings/ClientSettings.cs @@ -40,6 +40,7 @@ internal sealed record ClientAdvancedSettings(bool FormatOnType, bool AutoInsertAttributeQuotes, bool ColorBackground, bool CodeBlockBraceOnNextLine, + AttributeIndentStyle AttributeIndentStyle, bool CommitElementsWithSpace, SnippetSetting SnippetSetting, LogLevel LogLevel, @@ -51,6 +52,7 @@ internal sealed record ClientAdvancedSettings(bool FormatOnType, AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: false, + AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: true, SnippetSetting.All, LogLevel.Warning, @@ -65,6 +67,7 @@ public bool Equals(ClientAdvancedSettings? other) AutoInsertAttributeQuotes == other.AutoInsertAttributeQuotes && ColorBackground == other.ColorBackground && CodeBlockBraceOnNextLine == other.CodeBlockBraceOnNextLine && + AttributeIndentStyle == other.AttributeIndentStyle && CommitElementsWithSpace == other.CommitElementsWithSpace && SnippetSetting == other.SnippetSetting && LogLevel == other.LogLevel && @@ -80,6 +83,7 @@ public override int GetHashCode() hash.Add(AutoInsertAttributeQuotes); hash.Add(ColorBackground); hash.Add(CodeBlockBraceOnNextLine); + hash.Add(AttributeIndentStyle); hash.Add(CommitElementsWithSpace); hash.Add(SnippetSetting); hash.Add(LogLevel); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlineCompletionEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlineCompletionEndpoint.cs index 75de28abe78..0a5b89911fa 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlineCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlineCompletionEndpoint.cs @@ -94,7 +94,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie if (result.Range is not null) { - var options = RazorFormattingOptions.From(formattingOptions, _clientSettingsManager.GetClientSettings().AdvancedSettings.CodeBlockBraceOnNextLine); + var options = RazorFormattingOptions.From(formattingOptions, _clientSettingsManager.GetClientSettings().AdvancedSettings.CodeBlockBraceOnNextLine, _clientSettingsManager.GetClientSettings().AdvancedSettings.AttributeIndentStyle); var span = result.Range.ToLinePositionSpan(); var formattedInfo = await _remoteServiceInvoker.TryInvokeAsync( razorDocument.Project.Solution, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs index 01db1266b91..b2f79c4947a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs @@ -104,6 +104,7 @@ public ClientAdvancedSettings GetAdvancedSettings() GetBool(SettingsNames.AutoInsertAttributeQuotes, defaultValue: true), GetBool(SettingsNames.ColorBackground, defaultValue: false), GetBool(SettingsNames.CodeBlockBraceOnNextLine, defaultValue: false), + GetEnum(SettingsNames.AttributeIndentStyle, AttributeIndentStyle.AlignWithFirst), GetBool(SettingsNames.CommitElementsWithSpace, defaultValue: true), GetEnum(SettingsNames.Snippets, SnippetSetting.All), GetEnum(SettingsNames.LogLevel, LogLevel.Warning), diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs index 522b0b34d21..a7f5e4ad565 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs @@ -12,6 +12,7 @@ internal static class SettingsNames public static readonly string AutoInsertAttributeQuotes = UnifiedCollection + ".autoInsertAttributeQuotes"; public static readonly string ColorBackground = UnifiedCollection + ".colorBackground"; public static readonly string CodeBlockBraceOnNextLine = UnifiedCollection + ".codeBlockBraceOnNextLine"; + public static readonly string AttributeIndentStyle = UnifiedCollection + ".attributeIndentStyle"; public static readonly string CommitElementsWithSpace = UnifiedCollection + ".commitElementsWithSpace"; public static readonly string Snippets = UnifiedCollection + ".snippets"; public static readonly string LogLevel = UnifiedCollection + ".logLevel"; @@ -24,6 +25,7 @@ internal static class SettingsNames AutoInsertAttributeQuotes, ColorBackground, CodeBlockBraceOnNextLine, + AttributeIndentStyle, CommitElementsWithSpace, Snippets, LogLevel, diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.Custom.pkgdef b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.Custom.pkgdef index 17befdb8d65..0868efcb927 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.Custom.pkgdef +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.Custom.pkgdef @@ -55,4 +55,4 @@ [$RootKey$\SettingsManifests\{13b72f58-279e-49e0-a56d-296be02f0805}] @="Microsoft.VisualStudio.RazorExtension.RazorPackage" "ManifestPath"="$PackageFolder$\UnifiedSettings\razor.registration.json" -"CacheTag"=qword:91324F976E73CC56 +"CacheTag"=qword:91324F976E73CC57 diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/UnifiedSettings/razor.registration.json b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/UnifiedSettings/razor.registration.json index e6ae2e717e8..628f0260943 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/UnifiedSettings/razor.registration.json +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/UnifiedSettings/razor.registration.json @@ -84,11 +84,22 @@ "pass": { "input": { "store": "VsUserSettingsRegistry", - "path": "Razor\\CodeBlockBraceOnNextLined" + "path": "Razor\\CodeBlockBraceOnNextLine" } } } }, + "languages.razor.advanced.attributeIndentStyle": { + "type": "string", + "default": "alignWithFirst", + "enum": [ "alignWithFirst", "indentByOne" ], + "enumItemLabels": [ + "@Setting_AttributeIndentStyleAlignWithFirst;{13b72f58-279e-49e0-a56d-296be02f0805}", + "@Setting_AttributeIndentStyleIndentByOne;{13b72f58-279e-49e0-a56d-296be02f0805}" + ], + "title": "@Setting_AttributeIndentStyleDisplayName;{13b72f58-279e-49e0-a56d-296be02f0805}", + "description": "@Setting_AttributeIndentStyleDescription;{13b72f58-279e-49e0-a56d-296be02f0805}" + }, "languages.razor.advanced.commitElementsWithSpace": { "type": "boolean", "default": true, @@ -106,7 +117,7 @@ "languages.razor.advanced.snippets": { "type": "string", "default": "all", - "enum": ["all", "custom", "none"], + "enum": [ "all", "custom", "none" ], "enumItemLabels": [ "@Setting_SnippetsAll;{13b72f58-279e-49e0-a56d-296be02f0805}", "@Setting_SnippetsCustom;{13b72f58-279e-49e0-a56d-296be02f0805}", diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/VSPackage.resx b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/VSPackage.resx index 3668a911591..b7f70e6969c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/VSPackage.resx +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/VSPackage.resx @@ -237,4 +237,16 @@ Typing + + Attribute Indent Style + + + Defines how Html and component tag attributes should be indented + + + Align with first attribute + + + Indent by one level + \ No newline at end of file diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.cs.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.cs.xlf index c12b785defd..65744e7dd69 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.cs.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.cs.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Při hodnotě true se budou automaticky vkládat uzavírací značky. diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.de.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.de.xlf index cf637c2f4c4..d971fa849d3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.de.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.de.xlf @@ -42,6 +42,26 @@ Razor-Syntax-Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Bei "true" werden schließende Tags automatisch eingefügt. diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.es.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.es.xlf index 7800c1b8c6a..390029ed7ca 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.es.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.es.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Si es verdadero, las etiquetas de cierre se insertarán automáticamente diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.fr.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.fr.xlf index 0c271310789..1c1bbf3d92b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.fr.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.fr.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Si la valeur est true, les balises de fermeture sont automatiquement insérées diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.it.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.it.xlf index 51b4cac3329..bcff8d6a5bb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.it.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.it.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Se true, i tag di chiusura verranno inseriti automaticamente diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ja.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ja.xlf index 21e20d304db..b4f8383d6b4 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ja.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ja.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted true の場合、終了タグは自動的に挿入されます diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ko.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ko.xlf index fab0ddfb438..7787025a6bb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ko.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ko.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted true이면 닫는 태그가 자동으로 삽입됩니다. diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pl.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pl.xlf index 88b01a257d9..9fdc0182cb3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pl.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pl.xlf @@ -42,6 +42,26 @@ Syntax Visualizer Razor + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted W przypadku wartości true tagi zamykające będą wstawiane automatycznie diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pt-BR.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pt-BR.xlf index f3072c64291..859edd352cd 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pt-BR.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.pt-BR.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted Se verdadeiro, as tags de fechamento serão inseridas automaticamente diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ru.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ru.xlf index d8f4e972cc1..fa36a6f8603 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ru.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.ru.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted При значении true закрывающие теги вставляются автоматически diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.tr.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.tr.xlf index dc9d7ef13ad..172c3526c24 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.tr.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.tr.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted True ise, kapanış etiketleri otomatik olarak eklenir diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hans.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hans.xlf index 9fe3ccda9c3..e4d6e38e829 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hans.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hans.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted 如果为 true,将自动插入结束标记 diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hant.xlf b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hant.xlf index 32a598b3f36..84cc650689e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hant.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/VSPackage.zh-Hant.xlf @@ -42,6 +42,26 @@ Razor Syntax Visualizer + + Align with first attribute + Align with first attribute + + + + Defines how Html and component tag attributes should be indented + Defines how Html and component tag attributes should be indented + + + + Attribute Indent Style + Attribute Indent Style + + + + Indent by one level + Indent by one level + + If true, closing tags will be automatically inserted 若為 True,將會自動插入結尾標記 diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/CohostConfigurationChangedService.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/CohostConfigurationChangedService.cs index b721ab6653d..86e674e85da 100644 --- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/CohostConfigurationChangedService.cs +++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/CohostConfigurationChangedService.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Composition; using System.Text.Json.Nodes; using System.Threading; @@ -47,6 +48,7 @@ private async Task RefreshOptionsAsync(RazorCohostRequestContext requestContext, Items = [ //TODO: new ConfigurationItem { Section = "razor.format.enable" }, new ConfigurationItem { Section = "razor.format.code_block_brace_on_next_line" }, + new ConfigurationItem { Section = "razor.format.attribute_indent_style" }, new ConfigurationItem { Section = "razor.completion.commit_elements_with_space" }, ] }; @@ -60,7 +62,8 @@ private async Task RefreshOptionsAsync(RazorCohostRequestContext requestContext, var settings = current with { CodeBlockBraceOnNextLine = GetBooleanOptionValue(options[0], current.CodeBlockBraceOnNextLine), - CommitElementsWithSpace = GetBooleanOptionValue(options[1], current.CommitElementsWithSpace), + AttributeIndentStyle = GetEnumOptionValue(options[1], current.AttributeIndentStyle), + CommitElementsWithSpace = GetBooleanOptionValue(options[2], current.CommitElementsWithSpace), }; _clientSettingsManager.Update(settings); @@ -75,4 +78,19 @@ private static bool GetBooleanOptionValue(JsonNode? jsonNode, bool defaultValue) return jsonNode.ToString() == "true"; } + + private static T GetEnumOptionValue(JsonNode? jsonNode, T defaultValue) where T : struct + { + if (jsonNode is null) + { + return defaultValue; + } + + if (Enum.TryParse(jsonNode.GetValue(), out var value)) + { + return value; + } + + return defaultValue; + } } 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 da59332bea5..a8f1ec9c03b 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 @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Razor.CodeActions.Razor; using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Testing; using Xunit; using Xunit.Abstractions; @@ -843,6 +844,7 @@ public async Task Handle_GenerateMethod_VaryIndentSize(bool insertSpaces, int ta AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: false, + AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: true, TaskListDescriptors: []); var optionsMonitor = TestRazorLSPOptionsMonitor.Create(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorConfigurationServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorConfigurationServiceTest.cs index 428661a9ce2..d8089b556cd 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorConfigurationServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorConfigurationServiceTest.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; +using Microsoft.CodeAnalysis.Razor.Settings; using Moq; using Xunit; using Xunit.Abstractions; @@ -21,7 +22,7 @@ public async Task GetLatestOptionsAsync_ReturnsExpectedOptions() { // Arrange var expectedOptions = new RazorLSPOptions( - FormattingFlags.Disabled, AutoClosingTags: false, InsertSpaces: true, TabSize: 4, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: true, CommitElementsWithSpace: false, TaskListDescriptors: []); + FormattingFlags.Disabled, AutoClosingTags: false, InsertSpaces: true, TabSize: 4, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: true, AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: false, TaskListDescriptors: []); var razorJsonString = """ @@ -93,12 +94,13 @@ public void BuildOptions_VSCodeOptionsOnly_ReturnsExpected() { // Arrange - purposely choosing options opposite of default var expectedOptions = new RazorLSPOptions( - FormattingFlags.Disabled, AutoClosingTags: false, InsertSpaces: true, TabSize: 4, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: true, CommitElementsWithSpace: false, TaskListDescriptors: []); + FormattingFlags.Disabled, AutoClosingTags: false, InsertSpaces: true, TabSize: 4, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: true, AttributeIndentStyle: AttributeIndentStyle.IndentByOne, CommitElementsWithSpace: false, TaskListDescriptors: []); var razorJsonString = """ { "format": { "enable": false, - "codeBlockBraceOnNextLine": true + "codeBlockBraceOnNextLine": true, + "attributeIndentStyle": "indentByOne" } } @@ -130,7 +132,7 @@ public void BuildOptions_VSOptionsOnly_ReturnsExpected() { // Arrange - purposely choosing options opposite of default var expectedOptions = new RazorLSPOptions( - FormattingFlags.Enabled, AutoClosingTags: false, InsertSpaces: false, TabSize: 8, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: false, ColorBackground: false, CodeBlockBraceOnNextLine: false, CommitElementsWithSpace: false, TaskListDescriptors: []); + FormattingFlags.Enabled, AutoClosingTags: false, InsertSpaces: false, TabSize: 8, AutoShowCompletion: true, AutoListParams: true, AutoInsertAttributeQuotes: false, ColorBackground: false, CodeBlockBraceOnNextLine: false, CommitElementsWithSpace: false, AttributeIndentStyle: AttributeIndentStyle.IndentByOne, TaskListDescriptors: []); var razorJsonString = """ { } @@ -151,7 +153,8 @@ public void BuildOptions_VSOptionsOnly_ReturnsExpected() "FormatOnType": false, "AutoClosingTags": false, "AutoInsertAttributeQuotes": false, - "CommitElementsWithSpace": false + "CommitElementsWithSpace": false, + "AttributeIndentStyle": 1 } } """; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentFormattingTest.cs index b28f4628091..ee0faf7dee3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentFormattingTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentFormattingTest.cs @@ -7492,6 +7492,70 @@ public Task HtmlAttributes() """); + [FormattingTestFact] + public Task HtmlAttributes_FirstAttributeOnNextLine() + => RunFormattingTestAsync( + input: """ +
+
+ """, + expected: """ +
+
+ """); + + [FormattingTestFact] + public Task HtmlAttributes_IndentByOne() + => RunFormattingTestAsync( + input: """ + + """, + expected: """ + + """, + attributeIndentStyle: CodeAnalysis.Razor.Settings.AttributeIndentStyle.IndentByOne); + [FormattingTestFact] [WorkItem("https://github.com/dotnet/razor/issues/12223")] public Task ExplicitExpression_InIf() 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 5b45402332f..0f88488a3c2 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 @@ -24,7 +24,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Telemetry; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Moq; @@ -59,13 +59,18 @@ private protected async Task RunFormattingTestAsync( TagHelperCollection? tagHelpers = null, bool allowDiagnostics = false, bool codeBlockBraceOnNextLine = false, + AttributeIndentStyle attributeIndentStyle = AttributeIndentStyle.AlignWithFirst, bool inGlobalNamespace = false, bool debugAssertsEnabled = true, RazorCSharpSyntaxFormattingOptions? csharpSyntaxFormattingOptions = null) { (input, expected) = ProcessFormattingContext(input, expected); - var razorLSPOptions = RazorLSPOptions.Default with { CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine }; + var razorLSPOptions = RazorLSPOptions.Default with + { + CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine, + AttributeIndentStyle = attributeIndentStyle, + }; csharpSyntaxFormattingOptions ??= RazorCSharpSyntaxFormattingOptions.Default; @@ -106,7 +111,7 @@ private async Task RunFormattingTestInternalAsync( TabSize = tabSize, InsertSpaces = insertSpaces, }; - var razorOptions = RazorFormattingOptions.From(options, codeBlockBraceOnNextLine: razorLSPOptions?.CodeBlockBraceOnNextLine ?? false, csharpSyntaxFormattingOptions); + var razorOptions = RazorFormattingOptions.From(options, codeBlockBraceOnNextLine: razorLSPOptions?.CodeBlockBraceOnNextLine ?? false, razorLSPOptions?.AttributeIndentStyle ?? AttributeIndentStyle.AlignWithFirst, csharpSyntaxFormattingOptions); var languageServerFeatureOptions = new TestLanguageServerFeatureOptions(); @@ -172,7 +177,7 @@ private protected async Task RunOnTypeFormattingTestAsync( TabSize = tabSize, InsertSpaces = insertSpaces, }; - var razorOptions = RazorFormattingOptions.From(options, codeBlockBraceOnNextLine: razorLSPOptions?.CodeBlockBraceOnNextLine ?? false); + var razorOptions = RazorFormattingOptions.From(options, codeBlockBraceOnNextLine: razorLSPOptions?.CodeBlockBraceOnNextLine ?? false, razorLSPOptions?.AttributeIndentStyle ?? AttributeIndentStyle.AlignWithFirst); var documentContext = new DocumentContext(uri, documentSnapshot, projectContext: null); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorLSPOptionsMonitorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorLSPOptionsMonitorTest.cs index df1f08b8bb0..0664ab51bb8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorLSPOptionsMonitorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorLSPOptionsMonitorTest.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common; +using Microsoft.CodeAnalysis.Razor.Settings; using Moq; using Xunit; using Xunit.Abstractions; @@ -24,6 +25,7 @@ public class RazorLSPOptionsMonitorTest(ITestOutputHelper testOutput) : ToolingT AutoInsertAttributeQuotes: true, ColorBackground: false, CodeBlockBraceOnNextLine: false, + AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: true, TaskListDescriptors: []); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs index ec292c917e5..a278ffe81f0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Xunit.Abstractions; @@ -138,6 +139,7 @@ private protected static RazorLSPOptionsMonitor GetOptionsMonitor( bool autoInsertAttributeQuotes = true, bool colorBackground = false, bool codeBlockBraceOnNextLine = false, + AttributeIndentStyle attributeIndentStyle = AttributeIndentStyle.AlignWithFirst, bool commitElementsWithSpace = true, bool formatOnPaste = true) { @@ -153,6 +155,7 @@ private protected static RazorLSPOptionsMonitor GetOptionsMonitor( autoInsertAttributeQuotes, colorBackground, codeBlockBraceOnNextLine, + attributeIndentStyle, commitElementsWithSpace, TaskListDescriptors: []); var optionsMonitor = new RazorLSPOptionsMonitor(configService, options); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingLogTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingLogTest.cs index 1f31c6067b0..d45e315dcd5 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingLogTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingLogTest.cs @@ -44,7 +44,7 @@ public async Task UnexpectedFalseInIndentBlockOperation() var sourceText = await document.GetTextAsync(); var htmlEdits = htmlChanges.Select(c => sourceText.GetTextEdit(c.ToTextChange())).ToArray(); - await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, options.InsertSpaces, options.TabSize, options.CSharpSyntaxFormattingOptions.AssumeNotNull()); + await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, options.AttributeIndentStyle, options.InsertSpaces, options.TabSize, options.CSharpSyntaxFormattingOptions.AssumeNotNull()); } [Fact] @@ -91,7 +91,7 @@ public async Task CSharpStringLiteral() var sourceText = await document.GetTextAsync(); var htmlEdits = htmlChanges.Select(c => sourceText.GetTextEdit(c.ToTextChange())).ToArray(); - return await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, options.InsertSpaces, options.TabSize, RazorCSharpSyntaxFormattingOptions.Default); + return await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, options.AttributeIndentStyle, options.InsertSpaces, options.TabSize, RazorCSharpSyntaxFormattingOptions.Default); } private string GetResource(string name, [CallerMemberName] string? testName = null) diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingTestBase.cs index ec4a0569e77..2c188ed6297 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/FormattingTestBase.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Razor.Settings; @@ -41,6 +42,7 @@ private protected async Task RunFormattingTestAsync( RazorFileKind? fileKind = null, bool inGlobalNamespace = false, bool codeBlockBraceOnNextLine = false, + AttributeIndentStyle attributeIndentStyle = AttributeIndentStyle.AlignWithFirst, bool insertSpaces = true, int tabSize = 4, bool allowDiagnostics = false, @@ -82,7 +84,7 @@ private protected async Task RunFormattingTestAsync( ? spans.First() : default; - var edits = await GetFormattingEditsAsync(document, htmlEdits, span, codeBlockBraceOnNextLine, insertSpaces, tabSize, csharpSyntaxFormattingOptions); + var edits = await GetFormattingEditsAsync(document, htmlEdits, span, codeBlockBraceOnNextLine, attributeIndentStyle, insertSpaces, tabSize, csharpSyntaxFormattingOptions); if (edits is null) { @@ -97,12 +99,16 @@ private protected async Task RunFormattingTestAsync( AssertEx.EqualOrDiff(expected, finalText.ToString()); } - private protected async Task GetFormattingEditsAsync(TextDocument document, TextEdit[]? htmlEdits, TextSpan span, bool codeBlockBraceOnNextLine, bool insertSpaces, int tabSize, RazorCSharpSyntaxFormattingOptions csharpSyntaxFormattingOptions) + private protected async Task GetFormattingEditsAsync(TextDocument document, TextEdit[]? htmlEdits, TextSpan span, bool codeBlockBraceOnNextLine, AttributeIndentStyle attributeIndentStyle, bool insertSpaces, int tabSize, RazorCSharpSyntaxFormattingOptions csharpSyntaxFormattingOptions) { var requestInvoker = new TestHtmlRequestInvoker([(Methods.TextDocumentFormattingName, htmlEdits)]); var clientSettingsManager = new ClientSettingsManager(changeTriggers: []); - clientSettingsManager.Update(clientSettingsManager.GetClientSettings().AdvancedSettings with { CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine }); + clientSettingsManager.Update(clientSettingsManager.GetClientSettings().AdvancedSettings with + { + CodeBlockBraceOnNextLine = codeBlockBraceOnNextLine, + AttributeIndentStyle = attributeIndentStyle, + }); var edits = await GetFormattingEditsAsync(span, insertSpaces, tabSize, document, requestInvoker, clientSettingsManager, csharpSyntaxFormattingOptions); return edits; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/HtmlFormattingTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/HtmlFormattingTest.cs index 8648fcc85d3..6b319453a74 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/HtmlFormattingTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/Formatting/HtmlFormattingTest.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; using Microsoft.CodeAnalysis.Razor.Formatting; +using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; using Microsoft.VisualStudio.Razor.LanguageClient.Cohost.Formatting; using Xunit; @@ -426,8 +427,9 @@ await RunFormattingTestAsync( allowDiagnostics: true); } - [FormattingTestFact] - public async Task HtmlAttributes_FirstNotOnSameLine() + [FormattingTestTheory] + [CombinatorialData] + internal async Task HtmlAttributes_FirstNotOnSameLine(AttributeIndentStyle attributeIndentStyle) { // This test looks different because it explicitly doesn't call the html formatter, because we don't // want it to "fix" the first attribute placement, and put it on the same line as the start tag. @@ -464,7 +466,7 @@ public async Task HtmlAttributes_FirstNotOnSameLine() formattingService.GetTestAccessor().SetFormattingLoggerFactory(new TestFormattingLoggerFactory(TestOutputHelper)); var htmlEdits = new TextEdit[0]; - var edits = await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, options.InsertSpaces, options.TabSize, RazorCSharpSyntaxFormattingOptions.Default); + var edits = await GetFormattingEditsAsync(document, htmlEdits, span: default, options.CodeBlockBraceOnNextLine, attributeIndentStyle, options.InsertSpaces, options.TabSize, RazorCSharpSyntaxFormattingOptions.Default); Assert.NotNull(edits); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs index 8f117a6e6a4..2e87701686c 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs @@ -90,6 +90,7 @@ public void Update_TriggersChangedIfAdvancedSettingsAreDifferent() AutoInsertAttributeQuotes: true, ColorBackground: true, CodeBlockBraceOnNextLine: false, + AttributeIndentStyle: AttributeIndentStyle.AlignWithFirst, CommitElementsWithSpace: false, SnippetSetting: SnippetSetting.All, LogLevel: LogLevel.None,