Skip to content

Commit

Permalink
OnAutoInsert Cohosting Tests (#10829)
Browse files Browse the repository at this point in the history
* OnAutoInsert Cohosting Tests

* Fixing C# case (and correcting others)

All text should already be in the document/buffer when OnAutoInsert is being executed. Tigger character is not being added to the buffer, it should already be in the buffer.

* PR feedback

Switching to applying edit instead of verifying edit contents and range. Switching from Theories to separate Facts where input was complex. Other misc cleanup.

* Fixing options source and adding options tests

* Tests for all options

* Switching to use TestCode class

* Create options object for cohost OnAutoInsert to combined individual options passed to the remove service.

* More PR feedback

* Switching to nested RazorFormattingOptions
  • Loading branch information
alexgav committed Sep 6, 2024
1 parent 07e1382 commit e9cd0b2
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using RoslynFormattingOptions = Roslyn.LanguageServer.Protocol.FormattingOptions;

namespace Microsoft.CodeAnalysis.Razor.Formatting;

Expand Down Expand Up @@ -36,4 +37,11 @@ public RazorIndentationOptions ToIndentationOptions()
UseTabs: !InsertSpaces,
TabSize: TabSize,
IndentationSize: TabSize);

public RoslynFormattingOptions ToRoslynFormattingOptions()
=> new RoslynFormattingOptions()
{
InsertSpaces = InsertSpaces,
TabSize = TabSize
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@

using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Text;

using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.CodeAnalysis.Razor.Protocol.AutoInsert.RemoteAutoInsertTextEdit?>;

namespace Microsoft.CodeAnalysis.Razor.Remote;

internal interface IRemoteAutoInsertService
{
ValueTask<Response> GetAutoInsertTextEditAsync(
RazorPinnedSolutionInfoWrapper solutionInfo,
DocumentId documentId,
LinePosition position,
string character,
bool autoCloseTags,
bool formatOnType,
bool indentWithTabs,
int indentSize,
RemoteAutoInsertOptions options,
CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Razor.Formatting;
using Microsoft.CodeAnalysis.Razor.Settings;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.Razor.Remote;

[DataContract]
internal readonly record struct RemoteAutoInsertOptions
{
[DataMember(Order = 0)]
public bool EnableAutoClosingTags { get; init; } = true;

[DataMember(Order = 1)]
public bool FormatOnType { get; init; } = true;

[DataMember(Order = 2)]
public RazorFormattingOptions FormattingOptions { get; init; } = new RazorFormattingOptions()
{
InsertSpaces = true,
TabSize = 4
};

public RemoteAutoInsertOptions()
{
}

public static RemoteAutoInsertOptions From(ClientSettings clientSettings, FormattingOptions formattingOptions)
=> new()
{
EnableAutoClosingTags = clientSettings.AdvancedSettings.AutoClosingTags,
FormatOnType = clientSettings.AdvancedSettings.FormatOnType,
FormattingOptions = RazorFormattingOptions.From(formattingOptions, codeBlockBraceOnNextLine: false)
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Protocol;
using Microsoft.CodeAnalysis.Razor.Protocol.AutoInsert;
using Microsoft.CodeAnalysis.Razor.Remote;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Roslyn.LanguageServer.Protocol;
using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.CodeAnalysis.Razor.Protocol.AutoInsert.RemoteAutoInsertTextEdit?>;
using RoslynFormattingOptions = Roslyn.LanguageServer.Protocol.FormattingOptions;
using RoslynInsertTextFormat = Roslyn.LanguageServer.Protocol.InsertTextFormat;

namespace Microsoft.CodeAnalysis.Remote.Razor;
Expand All @@ -42,10 +42,7 @@ public ValueTask<Response> GetAutoInsertTextEditAsync(
DocumentId documentId,
LinePosition linePosition,
string character,
bool autoCloseTags,
bool formatOnType,
bool indentWithTabs,
int indentSize,
RemoteAutoInsertOptions options,
CancellationToken cancellationToken)
=> RunServiceAsync(
solutionInfo,
Expand All @@ -54,21 +51,15 @@ public ValueTask<Response> GetAutoInsertTextEditAsync(
context,
linePosition,
character,
autoCloseTags,
formatOnType,
indentWithTabs,
indentSize,
options,
cancellationToken),
cancellationToken);

private async ValueTask<Response> TryResolveInsertionAsync(
RemoteDocumentContext remoteDocumentContext,
LinePosition linePosition,
string character,
bool autoCloseTags,
bool formatOnType,
bool indentWithTabs,
int indentSize,
RemoteAutoInsertOptions options,
CancellationToken cancellationToken)
{
var sourceText = await remoteDocumentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false);
Expand All @@ -86,7 +77,7 @@ private async ValueTask<Response> TryResolveInsertionAsync(
codeDocument,
VsLspExtensions.ToPosition(linePosition),
character,
autoCloseTags,
options.EnableAutoClosingTags,
out var insertTextEdit))
{
return Response.Results(RemoteAutoInsertTextEdit.FromLspInsertTextEdit(insertTextEdit));
Expand All @@ -110,9 +101,7 @@ private async ValueTask<Response> TryResolveInsertionAsync(
remoteDocumentContext,
mappedPosition,
character,
formatOnType,
indentWithTabs,
indentSize,
options,
cancellationToken);
default:
Logger.LogError($"Unsupported language {languageKind} in {nameof(RemoteAutoInsertService)}");
Expand All @@ -124,9 +113,7 @@ private async ValueTask<Response> TryResolveInsertionInCSharpAsync(
RemoteDocumentContext remoteDocumentContext,
LinePosition mappedPosition,
string character,
bool formatOnType,
bool indentWithTabs,
int indentSize,
RemoteAutoInsertOptions options,
CancellationToken cancellationToken)
{
// Special case for C# where we use AutoInsert for two purposes:
Expand All @@ -140,7 +127,7 @@ private async ValueTask<Response> TryResolveInsertionInCSharpAsync(
// Therefore we are just going to no-op if the user has turned off on type formatting. Maybe one day we can make this
// smarter, but at least the user can always turn the setting back on, type their "///", and turn it back off, without
// having to restart VS. Not the worst compromise (hopefully!)
if (!formatOnType)
if (!options.FormatOnType)
{
return Response.NoFurtherHandling;
}
Expand All @@ -151,17 +138,12 @@ private async ValueTask<Response> TryResolveInsertionInCSharpAsync(
}

var generatedDocument = await remoteDocumentContext.Snapshot.GetGeneratedDocumentAsync().ConfigureAwait(false);
var formattingOptions = new RoslynFormattingOptions()
{
InsertSpaces = !indentWithTabs,
TabSize = indentSize
};

var autoInsertResponseItem = await OnAutoInsert.GetOnAutoInsertResponseAsync(
generatedDocument,
mappedPosition,
character,
formattingOptions,
options.FormattingOptions.ToRoslynFormattingOptions(),
cancellationToken
);

Expand All @@ -170,11 +152,7 @@ private async ValueTask<Response> TryResolveInsertionInCSharpAsync(
return Response.NoFurtherHandling;
}

var razorFormattingOptions = new RazorFormattingOptions()
{
InsertSpaces = !indentWithTabs,
TabSize = indentSize
};
var razorFormattingOptions = options.FormattingOptions;

var vsLspTextEdit = VsLspFactory.CreateTextEdit(
autoInsertResponseItem.TextEdit.Range.ToLinePositionSpan(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,15 @@ private static ImmutableArray<string> CalculateTriggerChars(IEnumerable<IOnAutoI
protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(VSInternalDocumentOnAutoInsertParams request)
=> request.TextDocument.ToRazorTextDocumentIdentifier();

protected override async Task<VSInternalDocumentOnAutoInsertResponseItem?> HandleRequestAsync(VSInternalDocumentOnAutoInsertParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
{
var razorDocument = context.TextDocument.AssumeNotNull();
protected override Task<VSInternalDocumentOnAutoInsertResponseItem?> HandleRequestAsync(VSInternalDocumentOnAutoInsertParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
=> HandleRequestAsync(request, context.TextDocument.AssumeNotNull(), cancellationToken);

private async Task<VSInternalDocumentOnAutoInsertResponseItem?> HandleRequestAsync(VSInternalDocumentOnAutoInsertParams request, TextDocument razorDocument, CancellationToken cancellationToken)
{
_logger.LogDebug($"Resolving auto-insertion for {razorDocument.FilePath}");

var clientSettings = _clientSettingsManager.GetClientSettings();
var enableAutoClosingTags = clientSettings.AdvancedSettings.AutoClosingTags;
var formatOnType = clientSettings.AdvancedSettings.FormatOnType;
var indentWithTabs = clientSettings.ClientSpaceSettings.IndentWithTabs;
var indentSize = clientSettings.ClientSpaceSettings.IndentSize;
var autoInsertOptions = RemoteAutoInsertOptions.From(clientSettings, request.Options);

_logger.LogDebug($"Calling OOP to resolve insertion at {request.Position} invoked by typing '{request.Character}'");
var data = await _remoteServiceInvoker.TryInvokeAsync<IRemoteAutoInsertService, Response>(
Expand All @@ -106,10 +104,7 @@ private static ImmutableArray<string> CalculateTriggerChars(IEnumerable<IOnAutoI
razorDocument.Id,
request.Position.ToLinePosition(),
request.Character,
enableAutoClosingTags,
formatOnType,
indentWithTabs,
indentSize,
autoInsertOptions,
cancellationToken),
cancellationToken).ConfigureAwait(false);

Expand Down Expand Up @@ -173,4 +168,15 @@ private static ImmutableArray<string> CalculateTriggerChars(IEnumerable<IOnAutoI

return result.Response;
}

internal TestAccessor GetTestAccessor() => new(this);

internal readonly struct TestAccessor(CohostOnAutoInsertEndpoint instance)
{
public Task<VSInternalDocumentOnAutoInsertResponseItem?> HandleRequestAsync(
VSInternalDocumentOnAutoInsertParams request,
TextDocument razorDocument,
CancellationToken cancellationToken)
=> instance.HandleRequestAsync(request, razorDocument, cancellationToken);
}
}
Loading

0 comments on commit e9cd0b2

Please sign in to comment.