Skip to content

Commit a3d678e

Browse files
authored
Merge pull request #7333 from dotnet/dev/jorobich/razor-project-context
Enable Project Context status item for Razor files
2 parents b1a2e1d + d79b0ca commit a3d678e

File tree

5 files changed

+53
-10
lines changed

5 files changed

+53
-10
lines changed

src/lsptoolshost/languageStatusBar.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,13 @@ class WorkspaceStatus {
5050

5151
class ProjectContextStatus {
5252
static createStatusItem(context: vscode.ExtensionContext, languageServer: RoslynLanguageServer) {
53+
const documentSelector = combineDocumentSelectors(
54+
languageServerOptions.documentSelector,
55+
RazorLanguage.documentSelector
56+
);
5357
const projectContextService = languageServer._projectContextService;
5458

55-
const item = vscode.languages.createLanguageStatusItem(
56-
'csharp.projectContextStatus',
57-
languageServerOptions.documentSelector
58-
);
59+
const item = vscode.languages.createLanguageStatusItem('csharp.projectContextStatus', documentSelector);
5960
item.name = vscode.l10n.t('C# Project Context Status');
6061
item.detail = vscode.l10n.t('Active File Context');
6162
context.subscriptions.push(item);

src/lsptoolshost/services/projectContextService.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { TextDocumentIdentifier } from 'vscode-languageserver-protocol';
1010
import { UriConverter } from '../uriConverter';
1111
import { LanguageServerEvents } from '../languageServerEvents';
1212
import { ServerState } from '../serverStateChange';
13+
import { DynamicFileInfoHandler } from '../../razor/src/dynamicFile/dynamicFileInfoHandler';
14+
import { ProvideDynamicFileResponse } from '../../razor/src/dynamicFile/provideDynamicFileResponse';
15+
import { ProvideDynamicFileParams } from '../../razor/src/dynamicFile/provideDynamicFileParams';
1316

1417
export interface ProjectContextChangeEvent {
1518
uri: vscode.Uri;
@@ -39,11 +42,22 @@ export class ProjectContextService {
3942

4043
public async refresh() {
4144
const textEditor = vscode.window.activeTextEditor;
42-
if (textEditor?.document?.languageId !== 'csharp') {
45+
const languageId = textEditor?.document?.languageId;
46+
if (languageId !== 'csharp' && languageId !== 'aspnetcorerazor') {
4347
return;
4448
}
4549

46-
const uri = textEditor.document.uri;
50+
let uri = textEditor!.document.uri;
51+
52+
// If the active document is a Razor file, we need to map it back to a C# file.
53+
if (languageId === 'aspnetcorerazor') {
54+
const virtualUri = await this.getVirtualCSharpUri(uri);
55+
if (!virtualUri) {
56+
return;
57+
}
58+
59+
uri = virtualUri;
60+
}
4761

4862
// If we have an open request, cancel it.
4963
this._source.cancel();
@@ -58,6 +72,20 @@ export class ProjectContextService {
5872
this._contextChangeEmitter.fire({ uri, context });
5973
}
6074

75+
private async getVirtualCSharpUri(uri: vscode.Uri): Promise<vscode.Uri | undefined> {
76+
const response = await vscode.commands.executeCommand<ProvideDynamicFileResponse>(
77+
DynamicFileInfoHandler.provideDynamicFileInfoCommand,
78+
new ProvideDynamicFileParams([uri.fsPath])
79+
);
80+
81+
const responseUri = response.generatedFiles[0];
82+
if (!responseUri) {
83+
return undefined;
84+
}
85+
86+
return UriConverter.deserialize(responseUri);
87+
}
88+
6189
private async getProjectContexts(
6290
uri: vscode.Uri,
6391
token: vscode.CancellationToken

src/razor/src/document/razorDocumentSynchronizer.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ export class RazorDocumentSynchronizer {
119119
}
120120

121121
private removeSynchronization(context: SynchronizationContext) {
122+
context.dispose();
123+
122124
const documentKey = getUriPath(context.projectedDocument.uri);
123125
const synchronizations = this.synchronizations[documentKey];
124126
clearTimeout(context.timeoutId);
@@ -167,6 +169,11 @@ export class RazorDocumentSynchronizer {
167169
reject(reason);
168170
}
169171
},
172+
dispose: () => {
173+
while (rejectionsForCancel.length > 0) {
174+
rejectionsForCancel.pop();
175+
}
176+
},
170177
projectedDocumentSynchronized,
171178
onProjectedDocumentSynchronized,
172179
projectedTextDocumentSynchronized,
@@ -271,4 +278,5 @@ interface SynchronizationContext {
271278
readonly projectedTextDocumentSynchronized: () => void;
272279
readonly onProjectedTextDocumentSynchronized: Promise<void>;
273280
readonly cancel: (reason: string) => void;
281+
readonly dispose: () => void;
274282
}

test/razorIntegrationTests/formatting.integration.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as path from 'path';
77
import * as vscode from 'vscode';
8-
import { describe, beforeAll, afterAll, test, expect } from '@jest/globals';
8+
import { describe, beforeAll, afterAll, test, expect, beforeEach } from '@jest/globals';
99
import testAssetWorkspace from './testAssets/testAssetWorkspace';
1010
import * as integrationHelpers from '../integrationTests/integrationHelpers';
1111

@@ -20,10 +20,13 @@ describe(`Razor Formatting ${testAssetWorkspace.description}`, function () {
2020
const htmlConfig = vscode.workspace.getConfiguration('html');
2121
await htmlConfig.update('format.enable', true);
2222

23-
await integrationHelpers.openFileInWorkspaceAsync(path.join('Pages', 'BadlyFormatted.razor'));
2423
await integrationHelpers.activateCSharpExtension();
2524
});
2625

26+
beforeEach(async function () {
27+
await integrationHelpers.openFileInWorkspaceAsync(path.join('Pages', 'BadlyFormatted.razor'));
28+
});
29+
2730
afterAll(async () => {
2831
await testAssetWorkspace.cleanupWorkspace();
2932
});

test/razorIntegrationTests/hover.integration.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as path from 'path';
77
import * as vscode from 'vscode';
8-
import { describe, beforeAll, afterAll, test, expect } from '@jest/globals';
8+
import { describe, beforeAll, afterAll, test, expect, beforeEach } from '@jest/globals';
99
import testAssetWorkspace from './testAssets/testAssetWorkspace';
1010
import * as integrationHelpers from '../integrationTests/integrationHelpers';
1111

@@ -15,10 +15,13 @@ describe(`Razor Hover ${testAssetWorkspace.description}`, function () {
1515
return;
1616
}
1717

18-
await integrationHelpers.openFileInWorkspaceAsync(path.join('Pages', 'Index.cshtml'));
1918
await integrationHelpers.activateCSharpExtension();
2019
});
2120

21+
beforeEach(async function () {
22+
await integrationHelpers.openFileInWorkspaceAsync(path.join('Pages', 'Index.cshtml'));
23+
});
24+
2225
afterAll(async () => {
2326
await testAssetWorkspace.cleanupWorkspace();
2427
});

0 commit comments

Comments
 (0)