Skip to content

Commit a1d442e

Browse files
author
Andrew Hall
authored
Add SpanMapping for VS Code (#8225)
2 parents d3e1c70 + 4c590ee commit a1d442e

16 files changed

+297
-41
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
# 2.76.x
77

88
# 2.75.x
9+
* Bump Razor to 10.0.0-preview.25228.4 (PR: [#8225](https://github.com/dotnet/vscode-csharp/pull/8225))
10+
* Don't return null if we couldn't sync the document for breakpoint validation (PR: [#11790](https://github.com/dotnet/razor/pull/11790))
11+
* Add VS Code IMappingService (PR: [#11760](https://github.com/dotnet/razor/pull/11760))
12+
* Fix cases where there is a space in the URI (PR: [#11745](https://github.com/dotnet/razor/pull/11745))
913
* Bump Roslyn to 5.0.0-1.25224.9 (PR: [#8211](https://github.com/dotnet/vscode-csharp/pull/8211))
1014
* Update ICSharpCode.Decompiler to 9.1.0.7988(PR: [#78270](https://github.com/dotnet/roslyn/pull/78270))
1115
* Reduce allocations in NamespaceSymbol.GetExtensionContainers(PR: [#78243](https://github.com/dotnet/roslyn/pull/78243))

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"defaults": {
4343
"roslyn": "5.0.0-1.25224.9",
4444
"omniSharp": "1.39.12",
45-
"razor": "10.0.0-preview.25228.3",
45+
"razor": "10.0.0-preview.25228.4",
4646
"razorOmnisharp": "7.0.0-preview.23363.1",
4747
"xamlTools": "17.14.36010.33"
4848
},

src/lsptoolshost/razor/razorEndpoints.ts

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,51 +24,94 @@ import { DocumentColorHandler } from '../../razor/src/documentColor/documentColo
2424
import { razorOptions } from '../../shared/options';
2525
import { ColorPresentationHandler } from '../../razor/src/colorPresentation/colorPresentationHandler';
2626
import { ColorPresentation } from 'vscode-html-languageservice';
27+
import { DynamicFileInfoHandler } from '../../razor/src/dynamicFile/dynamicFileInfoHandler';
28+
import { ProvideDynamicFileParams } from '../../razor/src/dynamicFile/provideDynamicFileParams';
29+
import { ProvideDynamicFileResponse } from '../../razor/src/dynamicFile/provideDynamicFileResponse';
30+
import { RazorMapSpansParams } from '../../razor/src/mapping/razorMapSpansParams';
31+
import { RazorMapSpansResponse } from '../../razor/src/mapping/razorMapSpansResponse';
32+
import { MappingHandler } from '../../razor/src/mapping/mappingHandler';
33+
import { RazorMapTextChangesParams } from '../../razor/src/mapping/razorMapTextChangesParams';
34+
import { RazorMapTextChangesResponse } from '../../razor/src/mapping/razorMapTextChangesResponse';
2735

2836
export function registerRazorEndpoints(
2937
context: vscode.ExtensionContext,
30-
languageServer: RoslynLanguageServer,
38+
roslynLanguageServer: RoslynLanguageServer,
3139
razorLogger: RazorLogger,
3240
platformInfo: PlatformInformation
3341
) {
3442
const logNotificationType = new NotificationType<LogMessageParams>('razor/log');
35-
languageServer.registerOnNotificationWithParams(logNotificationType, (params) =>
43+
roslynLanguageServer.registerOnNotificationWithParams(logNotificationType, (params) =>
3644
razorLogger.log(params.message, params.type)
3745
);
3846

39-
if (!razorOptions.cohostingEnabled) {
40-
return;
47+
if (razorOptions.cohostingEnabled) {
48+
registerCohostingEndpoints();
49+
} else {
50+
registerNonCohostingEndpoints();
4151
}
4252

43-
const documentManager = new HtmlDocumentManager(platformInfo, razorLogger);
44-
context.subscriptions.push(documentManager.register());
53+
return;
4554

46-
registerRequestHandler<HtmlUpdateParameters, void>('razor/updateHtml', async (params) => {
47-
const uri = UriConverter.deserialize(params.textDocument.uri);
48-
await documentManager.updateDocumentText(uri, params.text);
49-
});
55+
//
56+
// Local Functions
57+
//
58+
function registerCohostingEndpoints() {
59+
const documentManager = new HtmlDocumentManager(platformInfo, razorLogger);
60+
context.subscriptions.push(documentManager.register());
5061

51-
registerRequestHandler<DocumentColorParams, ColorInformation[]>(DocumentColorRequest.method, async (params) => {
52-
const uri = UriConverter.deserialize(params.textDocument.uri);
53-
const document = await documentManager.getDocument(uri);
54-
55-
return await DocumentColorHandler.doDocumentColorRequest(document.uri);
56-
});
62+
registerRequestHandler<HtmlUpdateParameters, void>('razor/updateHtml', async (params) => {
63+
const uri = UriConverter.deserialize(params.textDocument.uri);
64+
await documentManager.updateDocumentText(uri, params.text);
65+
});
5766

58-
registerRequestHandler<ColorPresentationParams, ColorPresentation[]>(
59-
ColorPresentationRequest.method,
60-
async (params) => {
67+
registerRequestHandler<DocumentColorParams, ColorInformation[]>(DocumentColorRequest.method, async (params) => {
6168
const uri = UriConverter.deserialize(params.textDocument.uri);
6269
const document = await documentManager.getDocument(uri);
6370

64-
return await ColorPresentationHandler.doColorPresentationRequest(document.uri, params);
65-
}
66-
);
71+
return await DocumentColorHandler.doDocumentColorRequest(document.uri);
72+
});
73+
74+
registerRequestHandler<ColorPresentationParams, ColorPresentation[]>(
75+
ColorPresentationRequest.method,
76+
async (params) => {
77+
const uri = UriConverter.deserialize(params.textDocument.uri);
78+
const document = await documentManager.getDocument(uri);
79+
80+
return await ColorPresentationHandler.doColorPresentationRequest(document.uri, params);
81+
}
82+
);
83+
}
84+
85+
function registerNonCohostingEndpoints() {
86+
registerRequestHandler<ProvideDynamicFileParams, ProvideDynamicFileResponse>(
87+
'razor/provideDynamicFileInfo',
88+
async (params) =>
89+
vscode.commands.executeCommand(DynamicFileInfoHandler.provideDynamicFileInfoCommand, params)
90+
);
91+
92+
registerRequestHandler<ProvideDynamicFileParams, ProvideDynamicFileResponse>(
93+
'razor/removeDynamicFileInfo',
94+
async (params) =>
95+
vscode.commands.executeCommand(DynamicFileInfoHandler.provideDynamicFileInfoCommand, params)
96+
);
97+
registerRequestHandler<RazorMapSpansParams, RazorMapSpansResponse>('razor/mapSpans', async (params) => {
98+
return await vscode.commands.executeCommand<RazorMapSpansResponse>(MappingHandler.MapSpansCommand, params);
99+
});
100+
registerRequestHandler<RazorMapTextChangesParams, RazorMapTextChangesResponse>(
101+
'razor/mapTextChanges',
102+
async (params) => {
103+
return await vscode.commands.executeCommand<RazorMapTextChangesResponse>(
104+
MappingHandler.MapChangesCommand,
105+
params
106+
);
107+
}
108+
);
109+
}
67110

68111
// Helper method that registers a request handler, and logs errors to the Razor logger.
69112
function registerRequestHandler<Params, Result>(method: string, invocation: (params: Params) => Promise<Result>) {
70113
const requestType = new RequestType<Params, Result, Error>(method);
71-
languageServer.registerOnRequest(requestType, async (params) => {
114+
roslynLanguageServer.registerOnRequest(requestType, async (params) => {
72115
try {
73116
return await invocation(params);
74117
} catch (error) {

src/razor/src/document/razorDocumentManager.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ export class RazorDocumentManager implements IRazorDocumentManager {
5656
return document;
5757
}
5858

59+
public async getDocumentForCSharpUri(csharpUri: vscode.Uri): Promise<IRazorDocument | undefined> {
60+
const csharpPath = csharpUri.fsPath ?? csharpUri.path;
61+
62+
return this.documents.find((document) => {
63+
if (this.platformInfo.isLinux()) {
64+
return document.csharpDocument.path === csharpPath;
65+
}
66+
67+
return document.csharpDocument.path.localeCompare(csharpPath, undefined, { sensitivity: 'base' }) === 0;
68+
});
69+
}
70+
5971
public async getActiveDocument(): Promise<IRazorDocument | null> {
6072
if (!vscode.window.activeTextEditor) {
6173
return null;

src/razor/src/dynamicFile/dynamicFileInfoHandler.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { RazorDynamicFileChangedParams } from './dynamicFileUpdatedParams';
1616
import { TextDocumentIdentifier } from 'vscode-languageserver-protocol';
1717
import { razorTextChange } from './razorTextChange';
1818
import { razorTextSpan } from './razorTextSpan';
19+
import { razorOptions } from '../../../shared/options';
1920

2021
// Handles Razor generated doc communication between the Roslyn workspace and Razor.
2122
// didChange behavior for Razor generated docs is handled in the RazorDocumentManager.
@@ -39,18 +40,21 @@ export class DynamicFileInfoHandler {
3940
await this.removeDynamicFileInfo(request);
4041
}
4142
);
42-
this.documentManager.onChange(async (e) => {
43-
// Ignore any updates without text changes. This is important for perf since sending an update to roslyn does
44-
// a round trip for producing nothing new and causes a lot of churn in solution updates.
45-
if (e.kind == RazorDocumentChangeKind.csharpChanged && !e.document.isOpen && e.changes.length > 0) {
46-
const uriString = UriConverter.serialize(e.document.uri);
47-
const identifier = TextDocumentIdentifier.create(uriString);
48-
await vscode.commands.executeCommand(
49-
DynamicFileInfoHandler.dynamicFileUpdatedCommand,
50-
new RazorDynamicFileChangedParams(identifier)
51-
);
52-
}
53-
});
43+
44+
if (!razorOptions.cohostingEnabled) {
45+
this.documentManager.onChange(async (e) => {
46+
// Ignore any updates without text changes. This is important for perf since sending an update to roslyn does
47+
// a round trip for producing nothing new and causes a lot of churn in solution updates.
48+
if (e.kind == RazorDocumentChangeKind.csharpChanged && !e.document.isOpen && e.changes.length > 0) {
49+
const uriString = UriConverter.serialize(e.document.uri);
50+
const identifier = TextDocumentIdentifier.create(uriString);
51+
await vscode.commands.executeCommand(
52+
DynamicFileInfoHandler.dynamicFileUpdatedCommand,
53+
new RazorDynamicFileChangedParams(identifier)
54+
);
55+
}
56+
});
57+
}
5458
}
5559

5660
// Given Razor document URIs, returns associated generated doc URIs

src/razor/src/extension.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { InlayHintHandler } from './inlayHint/inlayHintHandler';
5151
import { InlayHintResolveHandler } from './inlayHint/inlayHintResolveHandler';
5252
import { getComponentPaths } from '../../lsptoolshost/extensions/builtInComponents';
5353
import { BlazorDebugConfigurationProvider } from './blazorDebug/blazorDebugConfigurationProvider';
54+
import { MappingHandler } from './mapping/mappingHandler';
5455

5556
// We specifically need to take a reference to a particular instance of the vscode namespace,
5657
// otherwise providers attempt to operate on the null extension.
@@ -123,15 +124,15 @@ export async function activate(
123124
logger
124125
);
125126

126-
const languageServiceClient = new RazorLanguageServiceClient(languageServerClient);
127-
128127
const documentManager = new RazorDocumentManager(
129128
languageServerClient,
130129
logger,
131130
razorTelemetryReporter,
132131
platformInfo
133132
);
134133

134+
const languageServiceClient = new RazorLanguageServiceClient(languageServerClient, documentManager);
135+
135136
const documentSynchronizer = new RazorDocumentSynchronizer(documentManager, logger);
136137
reportTelemetryForDocuments(documentManager, razorTelemetryReporter);
137138
const languageConfiguration = new RazorLanguageConfiguration();
@@ -261,6 +262,8 @@ export async function activate(
261262
logger
262263
);
263264

265+
const mappingHandler = new MappingHandler(languageServiceClient);
266+
264267
localRegistrations.push(
265268
languageConfiguration.register(),
266269
vscodeType.languages.registerSignatureHelpProvider(RazorLanguage.id, signatureHelpProvider, '(', ','),
@@ -298,6 +301,7 @@ export async function activate(
298301
completionHandler.register(),
299302
razorSimplifyMethodHandler.register(),
300303
razorFormatNewFileHandler.register(),
304+
mappingHandler.register(),
301305
]);
302306
});
303307

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { RazorLanguageServiceClient } from '../razorLanguageServiceClient';
8+
import { RazorMapSpansParams } from './razorMapSpansParams';
9+
import { RazorMapTextChangesParams } from './razorMapTextChangesParams';
10+
11+
export class MappingHandler {
12+
public static readonly MapSpansCommand = 'razor.mapSpansCommand';
13+
public static readonly MapChangesCommand = 'razor.mapChangesCommand';
14+
15+
constructor(private readonly languageServiceClient: RazorLanguageServiceClient) {}
16+
17+
public async register(): Promise<vscode.Disposable> {
18+
return vscode.Disposable.from(
19+
...[
20+
vscode.commands.registerCommand(MappingHandler.MapSpansCommand, async (params: RazorMapSpansParams) => {
21+
return this.languageServiceClient.mapSpans(params);
22+
}),
23+
vscode.commands.registerCommand(
24+
MappingHandler.MapChangesCommand,
25+
async (params: RazorMapTextChangesParams) => {
26+
return this.languageServiceClient.mapTextChanges(params);
27+
}
28+
),
29+
]
30+
);
31+
}
32+
}

src/razor/src/mapping/mappingHelpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { RazorLanguageServiceClient } from '../razorLanguageServiceClient';
1010
import { RazorLogger } from '../razorLogger';
1111

1212
export class MappingHelpers {
13-
public readonly language = 'Razor';
13+
public static readonly language = 'Razor';
1414

1515
public static async remapGeneratedFileWorkspaceEdit(
1616
workspaceEdit: vscode.WorkspaceEdit,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { Range, TextDocumentIdentifier } from 'vscode-languageserver-protocol';
7+
8+
// Matches https://github.com/dotnet/razor/blob/main/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/RazorMapSpansParams.cs
9+
export class RazorMapSpansParams {
10+
constructor(public readonly csharpDocument: TextDocumentIdentifier, public readonly ranges: Range[]) {}
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { TextDocumentIdentifier } from 'vscode-languageserver-types';
7+
import { razorTextSpan } from '../dynamicFile/razorTextSpan';
8+
import { SerializableRange } from '../rpc/serializableRange';
9+
10+
// matches https://github.com/dotnet/razor/blob/main/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/RazorMapSpansResponse.cs
11+
export class RazorMapSpansResponse {
12+
static empty: RazorMapSpansResponse = new RazorMapSpansResponse([], [], { uri: '' });
13+
14+
constructor(
15+
public readonly ranges: SerializableRange[],
16+
public readonly spans: razorTextSpan[],
17+
public readonly razorDocument: TextDocumentIdentifier
18+
) {}
19+
}

0 commit comments

Comments
 (0)