Skip to content

Commit e2ec62a

Browse files
authored
Fix edit mapping for Html documents (#12027)
Fixes the integration tests that I broke when I removed Html source mappings. Also simplified the code actions and document color code, because they were the only two requesting from multiple language servers, which made debugging annoying, and is wasteful because we were getting empty responses from the ESLint server. We only work with the Html server in VS, and there is no point pretending otherwise.
2 parents a2c7019 + 28fd963 commit e2ec62a

File tree

4 files changed

+48
-90
lines changed

4 files changed

+48
-90
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractEditMappingService.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ private async Task<Dictionary<string, TextEdit[]>> RemapDocumentEditsAsync(IDocu
5555
{
5656
var generatedDocumentUri = new Uri(uriString);
5757

58+
// For Html we just map the Uri, the range will be the same
59+
if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri))
60+
{
61+
var razorUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri);
62+
remappedChanges[razorUri.AbsoluteUri] = edits;
63+
}
64+
5865
// Check if the edit is actually for a generated document, because if not we don't need to do anything
5966
if (!_filePathService.IsVirtualCSharpFile(generatedDocumentUri))
6067
{
@@ -111,6 +118,18 @@ private async Task<TextDocumentEdit[]> RemapTextDocumentEditsAsync(IDocumentSnap
111118
{
112119
var generatedDocumentUri = entry.TextDocument.DocumentUri.GetRequiredParsedUri();
113120

121+
// For Html we just map the Uri, the range will be the same
122+
if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri))
123+
{
124+
var razorUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri);
125+
entry.TextDocument = new OptionalVersionedTextDocumentIdentifier()
126+
{
127+
DocumentUri = new(razorUri),
128+
};
129+
remappedDocumentEdits.Add(entry);
130+
continue;
131+
}
132+
114133
// Check if the edit is actually for a generated document, because if not we don't need to do anything
115134
if (!_filePathService.IsVirtualCSharpFile(generatedDocumentUri))
116135
{

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions;
1111
using Microsoft.CodeAnalysis.Razor.Telemetry;
1212
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
13-
using Microsoft.VisualStudio.Threading;
1413
using StreamJsonRpc;
1514

1615
namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints;
@@ -54,33 +53,20 @@ internal partial class RazorCustomMessageTarget
5453

5554
codeActionParams.CodeActionParams.TextDocument.DocumentUri = new(virtualDocumentSnapshot.Uri);
5655

57-
var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer;
5856
var lspMethodName = Methods.TextDocumentCodeActionName;
5957
using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TelemetryThresholds.CodeActionSubLSPTelemetryThreshold, codeActionParams.CorrelationId);
60-
var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync<VSCodeActionParams, IReadOnlyList<VSInternalCodeAction>>(
61-
textBuffer,
58+
var response = await _requestInvoker.ReinvokeRequestOnServerAsync<VSCodeActionParams, IReadOnlyList<VSInternalCodeAction>>(
6259
lspMethodName,
60+
languageServerName,
6361
codeActionParams.CodeActionParams,
6462
cancellationToken).ConfigureAwait(false);
6563

66-
var codeActions = new List<VSInternalCodeAction>();
67-
await foreach (var response in requests.WithCancellation(cancellationToken).ConfigureAwait(false))
64+
if (response.Result is { } codeActions)
6865
{
69-
if (cancellationToken.IsCancellationRequested)
70-
{
71-
break;
72-
}
73-
74-
if (response.Response != null)
75-
{
76-
foreach (var codeAction in response.Response)
77-
{
78-
codeActions.Add(codeAction);
79-
}
80-
}
66+
return codeActions;
8167
}
8268

83-
return codeActions;
69+
return [];
8470
}
8571

8672
// Called by the Razor Language Server to resolve code actions from the platform.
@@ -94,19 +80,22 @@ internal partial class RazorCustomMessageTarget
9480

9581
bool synchronized;
9682
VirtualDocumentSnapshot virtualDocumentSnapshot;
83+
string languageServerName;
9784
if (resolveCodeActionParams.LanguageKind == RazorLanguageKind.Html)
9885
{
9986
(synchronized, virtualDocumentSnapshot) = await TrySynchronizeVirtualDocumentAsync<HtmlVirtualDocumentSnapshot>(
10087
resolveCodeActionParams.HostDocumentVersion,
10188
resolveCodeActionParams.Identifier,
10289
cancellationToken).ConfigureAwait(false);
90+
languageServerName = RazorLSPConstants.HtmlLanguageServerName;
10391
}
10492
else if (resolveCodeActionParams.LanguageKind == RazorLanguageKind.CSharp)
10593
{
10694
(synchronized, virtualDocumentSnapshot) = await TrySynchronizeVirtualDocumentAsync<CSharpVirtualDocumentSnapshot>(
10795
resolveCodeActionParams.HostDocumentVersion,
10896
resolveCodeActionParams.Identifier,
10997
cancellationToken).ConfigureAwait(false);
98+
languageServerName = RazorLSPConstants.RazorCSharpLanguageServerName;
11099
}
111100
else
112101
{
@@ -120,22 +109,17 @@ internal partial class RazorCustomMessageTarget
120109
return null;
121110
}
122111

123-
var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer;
124112
var codeAction = resolveCodeActionParams.CodeAction;
125113

126-
var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync<CodeAction, VSInternalCodeAction?>(
127-
textBuffer,
114+
var response = await _requestInvoker.ReinvokeRequestOnServerAsync<CodeAction, VSInternalCodeAction?>(
128115
Methods.CodeActionResolveName,
116+
languageServerName,
129117
codeAction,
130118
cancellationToken).ConfigureAwait(false);
131119

132-
await foreach (var response in requests.WithCancellation(cancellationToken).ConfigureAwait(false))
120+
if (response.Result is { } resolvedCodeAction)
133121
{
134-
if (response.Response is not null)
135-
{
136-
// Only take the first response from a resolution
137-
return response.Response;
138-
}
122+
return resolvedCodeAction;
139123
}
140124

141125
return null;

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_DocumentColor.cs

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Threading.Tasks;
88
using Microsoft.CodeAnalysis.Razor.Protocol;
99
using Microsoft.CodeAnalysis.Razor.Protocol.ColorPresentation;
10-
using Microsoft.VisualStudio.Threading;
1110
using StreamJsonRpc;
1211

1312
namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints;
@@ -26,27 +25,17 @@ internal partial class RazorCustomMessageTarget
2625
var (synchronized, htmlDoc) = await TrySynchronizeVirtualDocumentAsync<HtmlVirtualDocumentSnapshot>(documentColorParams.HostDocumentVersion, documentColorParams.TextDocument, cancellationToken);
2726
if (!synchronized || htmlDoc is null)
2827
{
29-
return new List<ColorInformation>();
28+
return [];
3029
}
3130

3231
documentColorParams.TextDocument.DocumentUri = new(htmlDoc.Uri);
33-
var htmlTextBuffer = htmlDoc.Snapshot.TextBuffer;
34-
var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync<DocumentColorParams, ColorInformation[]>(
35-
htmlTextBuffer,
32+
var response = await _requestInvoker.ReinvokeRequestOnServerAsync<DocumentColorParams, ColorInformation[]>(
3633
Methods.TextDocumentDocumentColor.Name,
34+
RazorLSPConstants.HtmlLanguageServerName,
3735
documentColorParams,
3836
cancellationToken).ConfigureAwait(false);
3937

40-
var colorInformation = new List<ColorInformation>();
41-
await foreach (var response in requests)
42-
{
43-
if (response.Response is not null)
44-
{
45-
colorInformation.AddRange(response.Response);
46-
}
47-
}
48-
49-
return colorInformation;
38+
return response.Result;
5039
}
5140

5241
// Called by the Razor Language Server to provide color presentation from the platform.
@@ -61,26 +50,16 @@ public async Task<IReadOnlyList<ColorPresentation>> ProvideHtmlColorPresentation
6150
var (synchronized, htmlDoc) = await TrySynchronizeVirtualDocumentAsync<HtmlVirtualDocumentSnapshot>(colorPresentationParams.RequiredHostDocumentVersion, colorPresentationParams.TextDocument, cancellationToken);
6251
if (!synchronized || htmlDoc is null)
6352
{
64-
return new List<ColorPresentation>();
53+
return [];
6554
}
6655

6756
colorPresentationParams.TextDocument.DocumentUri = new(htmlDoc.Uri);
68-
var htmlTextBuffer = htmlDoc.Snapshot.TextBuffer;
69-
var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync<ColorPresentationParams, ColorPresentation[]>(
70-
htmlTextBuffer,
57+
var response = await _requestInvoker.ReinvokeRequestOnServerAsync<ColorPresentationParams, ColorPresentation[]>(
7158
Methods.TextDocumentColorPresentationName,
59+
RazorLSPConstants.HtmlLanguageServerName,
7260
colorPresentationParams,
7361
cancellationToken).ConfigureAwait(false);
7462

75-
var colorPresentation = new List<ColorPresentation>();
76-
await foreach (var response in requests)
77-
{
78-
if (response.Response is not null)
79-
{
80-
colorPresentation.AddRange(response.Response);
81-
}
82-
}
83-
84-
return colorPresentation;
63+
return response.Result;
8564
}
8665
}

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Generic;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
using Azure;
1011
using Microsoft.AspNetCore.Razor.Test.Common;
1112
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
1213
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
@@ -242,26 +243,16 @@ public async Task ProvideCodeActionsAsync_ReturnsCodeActionsAsync()
242243
.Setup(manager => manager.TryGetDocument(It.IsAny<Uri>(), out testDocument))
243244
.Returns(true);
244245

245-
var languageServer1Response = new[] { new VSInternalCodeAction() { Title = "Response 1" } };
246-
var languageServer2Response = new[] { new VSInternalCodeAction() { Title = "Response 2" } };
246+
var languageServerResponse = new[] { new VSInternalCodeAction() { Title = "Response 1" } };
247247

248-
async IAsyncEnumerable<ReinvocationResponse<IReadOnlyList<VSInternalCodeAction>>> GetExpectedResultsAsync()
249-
{
250-
yield return new ReinvocationResponse<IReadOnlyList<VSInternalCodeAction>>("languageClient", languageServer1Response);
251-
yield return new ReinvocationResponse<IReadOnlyList<VSInternalCodeAction>>("languageClient", languageServer2Response);
252-
253-
await Task.CompletedTask;
254-
}
255-
256-
var expectedResults = GetExpectedResultsAsync();
257248
var requestInvoker = new Mock<LSPRequestInvoker>(MockBehavior.Strict);
258249
requestInvoker
259-
.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync<VSCodeActionParams, IReadOnlyList<VSInternalCodeAction>>(
260-
_textBuffer,
250+
.Setup(invoker => invoker.ReinvokeRequestOnServerAsync<VSCodeActionParams, IReadOnlyList<VSInternalCodeAction>>(
261251
Methods.TextDocumentCodeActionName,
252+
RazorLSPConstants.RazorCSharpLanguageServerName,
262253
It.IsAny<VSCodeActionParams>(),
263254
It.IsAny<CancellationToken>()))
264-
.Returns(expectedResults);
255+
.ReturnsAsync(new ReinvokeResponse<IReadOnlyList<VSInternalCodeAction>>(languageClient: null, languageServerResponse));
265256

266257
var documentSynchronizer = GetDocumentSynchronizer(GetCSharpSnapshot());
267258
var telemetryReporter = new Mock<ITelemetryReporter>(MockBehavior.Strict);
@@ -304,8 +295,7 @@ async IAsyncEnumerable<ReinvocationResponse<IReadOnlyList<VSInternalCodeAction>>
304295

305296
// Assert
306297
Assert.Collection(result,
307-
r => Assert.Equal(languageServer1Response[0].Title, r.Title),
308-
r => Assert.Equal(languageServer2Response[0].Title, r.Title));
298+
r => Assert.Equal(languageServerResponse[0].Title, r.Title));
309299
}
310300

311301
[Fact]
@@ -322,28 +312,14 @@ public async Task ResolveCodeActionsAsync_ReturnsSingleCodeAction()
322312
Title = "Something",
323313
Data = new object()
324314
};
325-
var unexpectedCodeAction = new VSInternalCodeAction()
326-
{
327-
Title = "Something Else",
328-
Data = new object()
329-
};
330-
331-
async IAsyncEnumerable<ReinvocationResponse<VSInternalCodeAction>> GetExpectedResultsAsync()
332-
{
333-
yield return new ReinvocationResponse<VSInternalCodeAction>("languageClient", expectedCodeAction);
334-
yield return new ReinvocationResponse<VSInternalCodeAction>("languageClient", unexpectedCodeAction);
335315

336-
await Task.CompletedTask;
337-
}
338-
339-
var expectedResponses = GetExpectedResultsAsync();
340316
requestInvoker
341-
.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync<CodeAction, VSInternalCodeAction>(
342-
It.IsAny<ITextBuffer>(),
317+
.Setup(invoker => invoker.ReinvokeRequestOnServerAsync<CodeAction, VSInternalCodeAction>(
343318
Methods.CodeActionResolveName,
319+
RazorLSPConstants.RazorCSharpLanguageServerName,
344320
It.IsAny<VSInternalCodeAction>(),
345321
It.IsAny<CancellationToken>()))
346-
.Returns(expectedResponses);
322+
.ReturnsAsync(new ReinvokeResponse<VSInternalCodeAction>(languageClient: null, expectedCodeAction));
347323

348324
var documentSynchronizer = new Mock<LSPDocumentSynchronizer>(MockBehavior.Strict);
349325
documentSynchronizer

0 commit comments

Comments
 (0)