Combine back into one on type formatting pass

This commit is contained in:
David Wengier 2024-08-21 14:29:29 +10:00
Родитель 97ac5367c7
Коммит 8984db9496
5 изменённых файлов: 21 добавлений и 76 удалений

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

@ -64,7 +64,7 @@ internal static class IServiceCollectionExtensions
// Formatting Passes
services.AddSingleton<IFormattingPass, HtmlFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpFormattingPass>();
services.AddSingleton<IFormattingPass, LspCSharpOnTypeFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpOnTypeFormattingPass>();
services.AddSingleton<IFormattingPass, FormattingDiagnosticValidationPass>();
services.AddSingleton<IFormattingPass, FormattingContentValidationPass>();
services.AddSingleton<IFormattingPass, LspRazorFormattingPass>();

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

@ -1,39 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.DocumentMapping;
using Microsoft.CodeAnalysis.Razor.Formatting;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
internal sealed class LspCSharpOnTypeFormattingPass(
IDocumentMappingService documentMappingService,
ILoggerFactory loggerFactory)
: CSharpOnTypeFormattingPassBase(documentMappingService, loggerFactory)
{
protected override async Task<TextEdit[]> AddUsingStatementEditsIfNecessaryAsync(CodeAnalysis.Razor.Formatting.FormattingContext context, RazorCodeDocument codeDocument, SourceText csharpText, TextEdit[] textEdits, SourceText originalTextWithChanges, TextEdit[] finalEdits, CancellationToken cancellationToken)
{
if (context.AutomaticallyAddUsings)
{
// Because we need to parse the C# code twice for this operation, lets do a quick check to see if its even necessary
if (textEdits.Any(e => e.NewText.IndexOf("using") != -1))
{
var usingStatementEdits = await AddUsingsHelper.GetUsingStatementEditsAsync(codeDocument, csharpText, originalTextWithChanges, cancellationToken).ConfigureAwait(false);
finalEdits = [.. usingStatementEdits, .. finalEdits];
}
}
return finalEdits;
}
}

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

@ -24,14 +24,12 @@ using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range;
namespace Microsoft.CodeAnalysis.Razor.Formatting;
using SyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode;
internal abstract class CSharpOnTypeFormattingPassBase(
internal sealed class CSharpOnTypeFormattingPass(
IDocumentMappingService documentMappingService,
ILoggerFactory loggerFactory)
: CSharpFormattingPassBase(documentMappingService)
{
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<CSharpOnTypeFormattingPassBase>();
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<CSharpOnTypeFormattingPass>();
public async override Task<FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
{
@ -208,7 +206,20 @@ internal abstract class CSharpOnTypeFormattingPassBase(
return new FormattingResult(finalEdits);
}
protected abstract Task<TextEdit[]> AddUsingStatementEditsIfNecessaryAsync(FormattingContext context, RazorCodeDocument codeDocument, SourceText csharpText, TextEdit[] textEdits, SourceText originalTextWithChanges, TextEdit[] finalEdits, CancellationToken cancellationToken);
private static async Task<TextEdit[]> AddUsingStatementEditsIfNecessaryAsync(CodeAnalysis.Razor.Formatting.FormattingContext context, RazorCodeDocument codeDocument, SourceText csharpText, TextEdit[] textEdits, SourceText originalTextWithChanges, TextEdit[] finalEdits, CancellationToken cancellationToken)
{
if (context.AutomaticallyAddUsings)
{
// Because we need to parse the C# code twice for this operation, lets do a quick check to see if its even necessary
if (textEdits.Any(e => e.NewText.IndexOf("using") != -1))
{
var usingStatementEdits = await AddUsingsHelper.GetUsingStatementEditsAsync(codeDocument, csharpText, originalTextWithChanges, cancellationToken).ConfigureAwait(false);
finalEdits = [.. usingStatementEdits, .. finalEdits];
}
}
return finalEdits;
}
// Returns the minimal TextSpan that encompasses all the differences between the old and the new text.
private static SourceText ApplyChangesAndTrackChange(SourceText oldText, IEnumerable<TextChange> changes, out TextSpan spanBeforeChange, out TextSpan spanAfterChange)
@ -323,7 +334,7 @@ internal abstract class CSharpOnTypeFormattingPassBase(
if (owner is CSharpStatementLiteralSyntax &&
owner.TryGetPreviousSibling(out var prevNode) &&
prevNode.FirstAncestorOrSelf<SyntaxNode>(a => a is CSharpTemplateBlockSyntax) is { } template &&
prevNode.FirstAncestorOrSelf<RazorSyntaxNode>(a => a is CSharpTemplateBlockSyntax) is { } template &&
owner.SpanStart == template.Span.End &&
IsOnSingleLine(template, text))
{
@ -477,7 +488,7 @@ internal abstract class CSharpOnTypeFormattingPassBase(
if (owner is CSharpStatementLiteralSyntax &&
owner.NextSpan() is { } nextNode &&
nextNode.FirstAncestorOrSelf<SyntaxNode>(a => a is CSharpTemplateBlockSyntax) is { } template &&
nextNode.FirstAncestorOrSelf<RazorSyntaxNode>(a => a is CSharpTemplateBlockSyntax) is { } template &&
template.SpanStart == owner.Span.End &&
IsOnSingleLine(template, text))
{
@ -523,7 +534,7 @@ internal abstract class CSharpOnTypeFormattingPassBase(
changes.Add(change);
}
private static bool IsOnSingleLine(SyntaxNode node, SourceText text)
private static bool IsOnSingleLine(RazorSyntaxNode node, SourceText text)
{
var linePositionSpan = text.GetLinePositionSpan(node.Span);

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

@ -1,27 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.DocumentMapping;
using Microsoft.CodeAnalysis.Razor.Formatting;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
internal sealed class RemoteCSharpOnTypeFormattingPass(
IDocumentMappingService documentMappingService,
ILoggerFactory loggerFactory)
: CSharpOnTypeFormattingPassBase(documentMappingService, loggerFactory)
{
protected override Task<TextEdit[]> AddUsingStatementEditsIfNecessaryAsync(CodeAnalysis.Razor.Formatting.FormattingContext context, RazorCodeDocument codeDocument, SourceText csharpText, TextEdit[] textEdits, SourceText originalTextWithChanges, TextEdit[] finalEdits, CancellationToken cancellationToken)
{
Debug.Fail("Implement this when code actions are migrated to cohosting");
return Task.FromResult(finalEdits);
}
}

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

@ -57,7 +57,7 @@ internal static class TestRazorFormattingService
{
new HtmlFormattingPass(mappingService, client, versionCache, loggerFactory),
new CSharpFormattingPass(mappingService, loggerFactory),
new LspCSharpOnTypeFormattingPass(mappingService, loggerFactory),
new CSharpOnTypeFormattingPass(mappingService, loggerFactory),
new LspRazorFormattingPass(mappingService, optionsMonitor),
new FormattingDiagnosticValidationPass(mappingService, loggerFactory),
new FormattingContentValidationPass(mappingService, loggerFactory),