Skip to content

Commit fa8dc89

Browse files
committed
Don't go all the way to oop just to access Html text
1 parent e792c19 commit fa8dc89

File tree

4 files changed

+55
-53
lines changed

4 files changed

+55
-53
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteWrapWithTagService.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,4 @@ namespace Microsoft.CodeAnalysis.Razor.Remote;
1111
internal interface IRemoteWrapWithTagService
1212
{
1313
ValueTask<RemoteResponse<LinePositionSpan>> GetValidWrappingRangeAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, LinePositionSpan range, CancellationToken cancellationToken);
14-
15-
ValueTask<RemoteResponse<TextEdit[]?>> FixHtmlTextEditsAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, TextEdit[] textEdits, CancellationToken cancellationToken);
1614
}

src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/WrapWithTag/RemoteWrapWithTagService.cs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33

44
using System.Threading;
55
using System.Threading.Tasks;
6-
using Microsoft.AspNetCore.Razor.Language;
76
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
8-
using Microsoft.CodeAnalysis.Razor.Formatting;
97
using Microsoft.CodeAnalysis.Razor.Remote;
108
using Microsoft.CodeAnalysis.Razor.Workspaces.Utilities;
119
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
1210
using Microsoft.CodeAnalysis.Text;
1311
using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.CodeAnalysis.Text.LinePositionSpan>;
14-
using TextEditResponse = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Roslyn.LanguageServer.Protocol.TextEdit[]?>;
1512

1613
namespace Microsoft.CodeAnalysis.Remote.Razor;
1714

@@ -34,17 +31,6 @@ public ValueTask<Response> GetValidWrappingRangeAsync(
3431
context => GetValidWrappingRangeAsync(context, range, cancellationToken),
3532
cancellationToken);
3633

37-
public ValueTask<TextEditResponse> FixHtmlTextEditsAsync(
38-
RazorPinnedSolutionInfoWrapper solutionInfo,
39-
DocumentId razorDocumentId,
40-
TextEdit[] textEdits,
41-
CancellationToken cancellationToken)
42-
=> RunServiceAsync(
43-
solutionInfo,
44-
razorDocumentId,
45-
context => FixHtmlTextEditsAsync(context, textEdits, cancellationToken),
46-
cancellationToken);
47-
4834
private static async ValueTask<Response> GetValidWrappingRangeAsync(
4935
RemoteDocumentContext context,
5036
LinePositionSpan range,
@@ -58,21 +44,4 @@ private static async ValueTask<Response> GetValidWrappingRangeAsync(
5844

5945
return Response.NoFurtherHandling;
6046
}
61-
62-
private async ValueTask<TextEditResponse> FixHtmlTextEditsAsync(
63-
RemoteDocumentContext context,
64-
TextEdit[] textEdits,
65-
CancellationToken cancellationToken)
66-
{
67-
if (textEdits.Length == 0)
68-
{
69-
return TextEditResponse.Results(textEdits);
70-
}
71-
72-
var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false);
73-
var htmlSourceText = codeDocument.GetHtmlSourceText();
74-
75-
var fixedEdits = FormattingUtilities.FixHtmlTextEdits(htmlSourceText, textEdits);
76-
return TextEditResponse.Results(fixedEdits);
77-
}
7847
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostWrapWithTagEndpoint.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Composition;
5+
using System.Linq;
56
using System.Threading;
67
using System.Threading.Tasks;
78
using Microsoft.AspNetCore.Razor;
89
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
911
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
12+
using Microsoft.CodeAnalysis.Razor.Formatting;
13+
using Microsoft.CodeAnalysis.Razor.Logging;
1014
using Microsoft.CodeAnalysis.Razor.Protocol;
1115
using Microsoft.CodeAnalysis.Razor.Remote;
1216
using Microsoft.CodeAnalysis.Text;
17+
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
1318
using Microsoft.VisualStudio.Razor.LanguageClient.WrapWithTag;
1419

1520
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
@@ -22,11 +27,15 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
2227
#pragma warning restore RS0030 // Do not use banned APIs
2328
internal sealed class CohostWrapWithTagEndpoint(
2429
IRemoteServiceInvoker remoteServiceInvoker,
25-
IHtmlRequestInvoker requestInvoker)
30+
IHtmlRequestInvoker requestInvoker,
31+
LSPDocumentManager documentManager,
32+
ILoggerFactory loggerFactory)
2633
: AbstractRazorCohostDocumentRequestHandler<VSInternalWrapWithTagParams, VSInternalWrapWithTagResponse?>
2734
{
2835
private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker;
2936
private readonly IHtmlRequestInvoker _requestInvoker = requestInvoker;
37+
private readonly LSPDocumentManager _documentManager = documentManager;
38+
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<CohostWrapWithTagEndpoint>();
3039

3140
protected override bool MutatesSolutionState => false;
3241

@@ -62,18 +71,28 @@ internal sealed class CohostWrapWithTagEndpoint(
6271
request,
6372
cancellationToken).ConfigureAwait(false);
6473

65-
if (htmlResponse?.TextEdits is not null)
74+
// If the Html response has ~s in it, then we need to clean them up.
75+
if (htmlResponse?.TextEdits is { } edits &&
76+
edits.Any(static e => e.NewText.Contains("~")))
6677
{
67-
// Fix the HTML text edits to handle any tilde characters in the generated document
68-
var fixedEdits = await _remoteServiceInvoker.TryInvokeAsync<IRemoteWrapWithTagService, RemoteResponse<TextEdit[]?>>(
69-
razorDocument.Project.Solution,
70-
(service, solutionInfo, cancellationToken) => service.FixHtmlTextEditsAsync(solutionInfo, razorDocument.Id, htmlResponse.TextEdits, cancellationToken),
71-
cancellationToken).ConfigureAwait(false);
78+
// To do this we don't actually need to go to OOP, we just need a SourceText with the Html document,
79+
// and we already have that in a virtual buffer, because it's what the above request was made against.
80+
// So we can write a little bit of code to grab that, and avoid the extra OOP call.
7281

73-
if (fixedEdits.Result is not null)
82+
if (!_documentManager.TryGetDocument(razorDocument.CreateUri(), out var snapshot))
7483
{
75-
htmlResponse.TextEdits = fixedEdits.Result;
84+
_logger.LogError($"Couldn't find document in LSPDocumentManager for {razorDocument.FilePath}");
85+
return null;
7686
}
87+
88+
if (!snapshot.TryGetVirtualDocument<HtmlVirtualDocumentSnapshot>(out var htmlDocument))
89+
{
90+
_logger.LogError($"Couldn't find virtual document snapshot for {snapshot.Uri}");
91+
return null;
92+
}
93+
94+
var htmlSourceText = SourceText.From(htmlDocument.Snapshot.GetText());
95+
htmlResponse.TextEdits = FormattingUtilities.FixHtmlTextEdits(htmlSourceText, edits);
7796
}
7897

7998
return htmlResponse;

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostWrapWithTagEndpointTest.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Threading.Tasks;
77
using Microsoft.AspNetCore.Razor.Test.Common;
8+
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
89
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
910
using Microsoft.CodeAnalysis.Razor.Protocol;
1011
using Microsoft.VisualStudio.Razor.LanguageClient.WrapWithTag;
@@ -74,37 +75,52 @@ public async Task HtmlWithTildes_FixesTextEdits()
7475
{
7576
await VerifyWrapWithTagAsync(
7677
input: """
77-
<div>
78-
@[||]currentCount
79-
</div>
80-
""",
78+
<div>
79+
@[||]currentCount
80+
</div>
81+
""",
82+
htmlDocument: """
83+
<div>
84+
/*~~~~~~~~~*/
85+
</div>
86+
""",
8187
expected: """
82-
<div>
83-
<span>@currentCount</span>
84-
</div>
85-
""",
88+
<div>
89+
<span>@currentCount</span>
90+
</div>
91+
""",
8692
htmlResponse: new VSInternalWrapWithTagResponse(
8793
LspFactory.CreateSingleLineRange(start: (1, 5), length: 13),
8894
[LspFactory.CreateTextEdit(1, 4, 1, 17, "<span>/*~~~~~~~~~*/</span>")]
8995
));
9096
}
9197

92-
private async Task VerifyWrapWithTagAsync(TestCode input, string? expected, VSInternalWrapWithTagResponse? htmlResponse)
98+
private async Task VerifyWrapWithTagAsync(TestCode input, string? expected, VSInternalWrapWithTagResponse? htmlResponse, string? htmlDocument = null)
9399
{
94100
var document = CreateProjectAndRazorDocument(input.Text);
95101
var sourceText = await document.GetTextAsync(DisposalToken);
96102

97103
var requestInvoker = new TestHtmlRequestInvoker([(LanguageServerConstants.RazorWrapWithTagEndpoint, htmlResponse)]);
98104

99-
var endpoint = new CohostWrapWithTagEndpoint(RemoteServiceInvoker, requestInvoker);
105+
var documentUri = document.CreateUri();
106+
var documentManager = new TestDocumentManager();
107+
if (htmlDocument is not null)
108+
{
109+
var snapshot = new StringTextSnapshot(htmlDocument);
110+
var htmlSnapshot = new HtmlVirtualDocumentSnapshot(documentUri, snapshot, hostDocumentSyncVersion: 1, state: null);
111+
var documentSnapshot = new TestLSPDocumentSnapshot(documentUri, version: 1, htmlSnapshot);
112+
documentManager.AddDocument(documentUri, documentSnapshot);
113+
}
114+
115+
var endpoint = new CohostWrapWithTagEndpoint(RemoteServiceInvoker, requestInvoker, documentManager, LoggerFactory);
100116

101117
var request = new VSInternalWrapWithTagParams(
102118
sourceText.GetRange(input.Span),
103119
"div",
104120
new FormattingOptions(),
105121
new VersionedTextDocumentIdentifier()
106122
{
107-
DocumentUri = new(document.CreateUri())
123+
DocumentUri = new(documentUri)
108124
});
109125

110126
var result = await endpoint.GetTestAccessor().HandleRequestAsync(request, document, DisposalToken);

0 commit comments

Comments
 (0)